diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 6e34c7a..2016ead 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4950,6 +4950,52 @@ struct mlx5_meter_domains_infos *
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
+/**
+ * Create policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter *fm,
+			       const struct rte_flow_attr *attr)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policer_rules(dev, fm, attr);
+}
+
+/**
+ * Destroy policer rules.
+ *
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter *fm,
+				const struct rte_flow_attr *attr)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->destroy_policer_rules(dev, fm, attr);
+}
+
 #define MLX5_POOL_QUERY_FREQ_US 1000000
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index d8f1537..489d7c0 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -559,6 +559,8 @@ struct mlx5_meter_domains_infos {
 struct mlx5_flow_meter {
 	uint32_t meter_id;
 	/**< Meter id. */
+	struct rte_mtr_params params;
+	/**< Meter rule parameters. */
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
 	uint32_t ref_cnt;
@@ -636,6 +638,14 @@ typedef int (*mlx5_flow_query_t)(struct rte_eth_dev *dev,
 					    (struct rte_eth_dev *dev);
 typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 					struct mlx5_meter_domains_infos *tbls);
+typedef int (*mlx5_flow_create_policer_rules_t)
+					(struct rte_eth_dev *dev,
+					 struct mlx5_flow_meter *fm,
+					 const struct rte_flow_attr *attr);
+typedef int (*mlx5_flow_destroy_policer_rules_t)
+					(struct rte_eth_dev *dev,
+					 const struct mlx5_flow_meter *fm,
+					 const struct rte_flow_attr *attr);
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
 	mlx5_flow_prepare_t prepare;
@@ -646,6 +656,8 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_query_t query;
 	mlx5_flow_create_mtr_tbls_t create_mtr_tbls;
 	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
+	mlx5_flow_create_policer_rules_t create_policer_rules;
+	mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
 };
 
 
@@ -776,4 +788,10 @@ struct mlx5_meter_domains_infos *mlx5_flow_create_mtr_tbls
 					(struct rte_eth_dev *dev);
 int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_meter_domains_infos *tbl);
+int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
+				   struct mlx5_flow_meter *fm,
+				   const struct rte_flow_attr *attr);
+int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
+				    struct mlx5_flow_meter *fm,
+				    const struct rte_flow_attr *attr);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index c0e5470..aa00b3e 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7660,6 +7660,9 @@ struct field_modify_info modify_tcp[] = {
 	return 0;
 }
 
+/* Number of meter flow actions, count and jump or count and drop. */
+#define METER_ACTIONS 2
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -7697,12 +7700,6 @@ struct field_modify_info modify_tcp[] = {
 		.match_criteria_enable = 0,
 		.match_mask = (void *)&mask,
 	};
-	/*
-	 * Need reserve two actions here. As for the meter flow, the action
-	 * to be performed will be jump or drop. The other reserve action is
-	 * for count.
-	 */
-#define METER_ACTIONS 2
 	void *actions[METER_ACTIONS];
 	struct mlx5_flow_tbl_resource **sfx_tbl;
 	struct mlx5_meter_domain_info *dtb;
@@ -7832,6 +7829,182 @@ struct field_modify_info modify_tcp[] = {
 	return NULL;
 }
 
+/**
+ * Destroy domain policer rule.
+ *
+ * @param[in] dt
+ *   Pointer to domain table.
+ */
+static void
+flow_dv_destroy_domain_policer_rule(struct mlx5_meter_domain_info *dt)
+{
+	int i;
+
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		if (dt->policer_rules[i]) {
+			claim_zero(mlx5_glue->dv_destroy_flow
+				  (dt->policer_rules[i]));
+			dt->policer_rules[i] = NULL;
+		}
+	}
+	if (dt->jump_actn) {
+		claim_zero(mlx5_glue->destroy_flow_action(dt->jump_actn));
+		dt->jump_actn = NULL;
+	}
+}
+
+/**
+ * Destroy policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,
+			      const struct mlx5_flow_meter *fm,
+			      const struct rte_flow_attr *attr)
+{
+	struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
+
+	if (!mtb)
+		return 0;
+	if (attr->egress)
+		flow_dv_destroy_domain_policer_rule(&mtb->egress);
+	if (attr->ingress)
+		flow_dv_destroy_domain_policer_rule(&mtb->ingress);
+	if (attr->transfer)
+		flow_dv_destroy_domain_policer_rule(&mtb->transfer);
+	return 0;
+}
+
+/**
+ * Create specify domain meter policer rule.
+ *
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] mtb
+ *   Pointer to DV meter table set.
+ * @param[in] sfx_tb
+ *   Pointer to suffix table.
+ * @param[in] mtr_reg_c
+ *   Color match REG_C.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
+				    struct mlx5_meter_domain_info *dtb,
+				    struct mlx5_flow_tbl_resource *sfx_tb,
+				    uint8_t mtr_reg_c)
+{
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf),
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf),
+	};
+	struct mlx5_meter_domains_infos *mtb = fm->mfts;
+	void *actions[METER_ACTIONS];
+	int i;
+
+	/* Create jump action. */
+	if (!sfx_tb)
+		return -1;
+	if (!dtb->jump_actn)
+		dtb->jump_actn =
+			mlx5_glue->dr_create_flow_action_dest_flow_tbl
+							(sfx_tb->obj);
+	if (!dtb->jump_actn) {
+		DRV_LOG(ERR, "Failed to create policer jump action.");
+		goto error;
+	}
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		int j = 0;
+
+		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,
+				       rte_col_2_mlx5_col(i), UINT32_MAX);
+		if (fm->params.action[i] == MTR_POLICER_ACTION_DROP)
+			actions[j++] = mtb->drop_actn;
+		else
+			actions[j++] = dtb->jump_actn;
+		dtb->policer_rules[i] =
+			mlx5_glue->dv_create_flow(dtb->color_matcher,
+						 (void *)&value,
+						  j, actions);
+		if (!dtb->policer_rules[i]) {
+			DRV_LOG(ERR, "Failed to create policer rule.");
+			goto error;
+		}
+	}
+	return 0;
+error:
+	rte_errno = errno;
+	return -1;
+}
+
+/**
+ * Create policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter *fm,
+			     const struct rte_flow_attr *attr)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_domains_infos *mtb = fm->mfts;
+	int ret;
+
+	if (attr->egress) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->egress,
+						priv->sh->tx_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create egress policer.");
+			goto error;
+		}
+	}
+	if (attr->ingress) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->ingress,
+						priv->sh->rx_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create ingress policer.");
+			goto error;
+		}
+	}
+	if (attr->transfer) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->transfer,
+						priv->sh->fdb_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create transfer policer.");
+			goto error;
+		}
+	}
+	return 0;
+error:
+	flow_dv_destroy_policer_rules(dev, fm, attr);
+	return -1;
+}
+
 /*
  * Mutex-protected thunk to lock-free  __flow_dv_translate().
  */
@@ -7899,6 +8072,8 @@ struct field_modify_info modify_tcp[] = {
 	.query = flow_dv_query,
 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
+	.create_policer_rules = flow_dv_create_policer_rules,
+	.destroy_policer_rules = flow_dv_destroy_policer_rules,
 };
 
 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
