diff --git a/drivers/net/nfp/nfp_mtr.c b/drivers/net/nfp/nfp_mtr.c
index 50efb56879..c8caf97262 100644
--- a/drivers/net/nfp/nfp_mtr.c
+++ b/drivers/net/nfp/nfp_mtr.c
@@ -371,10 +371,182 @@ nfp_mtr_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static struct nfp_mtr_policy *
+nfp_mtr_policy_search(struct nfp_mtr_priv *priv, uint32_t mtr_policy_id)
+{
+	struct nfp_mtr_policy *mtr_policy;
+
+	LIST_FOREACH(mtr_policy, &priv->policies, next)
+		if (mtr_policy->policy_id == mtr_policy_id)
+			break;
+
+	return mtr_policy;
+}
+
+static int
+nfp_mtr_policy_validate(uint32_t mtr_policy_id,
+		struct rte_mtr_meter_policy_params *policy,
+		struct rte_mtr_error *error)
+{
+	const struct rte_flow_action *action;
+
+	/* Policy must not be NULL */
+	if (policy == NULL) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Meter policy is null.");
+	}
+
+	/* Meter policy ID must be valid. */
+	if (mtr_policy_id >= NFP_MAX_POLICY_CNT) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+	}
+
+	/* Check green action
+	 * Actions equal NULL means end action
+	 */
+	action = policy->actions[RTE_COLOR_GREEN];
+	if (action != NULL && action->type != RTE_FLOW_ACTION_TYPE_VOID) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Green action must be void or end");
+	}
+
+	/* Check yellow action
+	 * Actions equal NULL means end action
+	 */
+	action = policy->actions[RTE_COLOR_YELLOW];
+	if (action != NULL && action->type != RTE_FLOW_ACTION_TYPE_VOID) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Yellow action must be void or end");
+	}
+
+	/* Check red action */
+	action = policy->actions[RTE_COLOR_RED];
+	if (action == NULL || action->type != RTE_FLOW_ACTION_TYPE_DROP) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Red action must be drop");
+	}
+
+	return 0;
+}
+
+/**
+ * Callback to add MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_policy_id
+ *   Meter policy id.
+ * @param[in] policy
+ *   Pointer to meter policy detail.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative value otherwise and rte_errno is set.
+ */
+static int
+nfp_mtr_policy_add(struct rte_eth_dev *dev,
+		uint32_t mtr_policy_id,
+		struct rte_mtr_meter_policy_params *policy,
+		struct rte_mtr_error *error)
+{
+	int ret;
+	struct nfp_mtr_priv *priv;
+	struct nfp_mtr_policy *mtr_policy;
+	struct nfp_flower_representor *representor;
+
+	representor = dev->data->dev_private;
+	priv = representor->app_fw_flower->mtr_priv;
+
+	/* Check if mtr policy id exist */
+	mtr_policy = nfp_mtr_policy_search(priv, mtr_policy_id);
+	if (mtr_policy != NULL) {
+		return -rte_mtr_error_set(error, EEXIST,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy already exist");
+	}
+
+	/* Check input params */
+	ret = nfp_mtr_policy_validate(mtr_policy_id, policy, error);
+	if (ret != 0)
+		return ret;
+
+	/* Meter policy memory alloc */
+	mtr_policy = rte_zmalloc(NULL, sizeof(struct nfp_mtr_policy), 0);
+	if (mtr_policy == NULL) {
+		return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+				NULL, "Meter policy alloc failed");
+	}
+
+	mtr_policy->policy_id = mtr_policy_id;
+	rte_memcpy(&mtr_policy->policy, policy,
+			sizeof(struct rte_mtr_meter_policy_params));
+
+	/* Insert policy into policy list */
+	LIST_INSERT_HEAD(&priv->policies, mtr_policy, next);
+
+	return 0;
+}
+
+/**
+ * Callback to delete MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_policy_id
+ *   Meter policy id.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative value otherwise and rte_errno is set.
+ */
+static int
+nfp_mtr_policy_delete(struct rte_eth_dev *dev,
+		uint32_t mtr_policy_id,
+		struct rte_mtr_error *error)
+{
+	struct nfp_mtr_priv *priv;
+	struct nfp_mtr_policy *mtr_policy;
+	struct nfp_flower_representor *representor;
+
+	representor = dev->data->dev_private;
+	priv = representor->app_fw_flower->mtr_priv;
+
+	/* Check if mtr policy id exist */
+	mtr_policy = nfp_mtr_policy_search(priv, mtr_policy_id);
+	if (mtr_policy == NULL) {
+		return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Request meter policy not exist");
+	}
+
+	if (mtr_policy->ref_cnt > 0) {
+		return -rte_mtr_error_set(error, EBUSY,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Request mtr policy is been used");
+	}
+
+	/* Remove profile from profile list */
+	LIST_REMOVE(mtr_policy, next);
+	rte_free(mtr_policy);
+
+	return 0;
+}
+
 static const struct rte_mtr_ops nfp_mtr_ops = {
 	.capabilities_get      = nfp_mtr_cap_get,
 	.meter_profile_add     = nfp_mtr_profile_add,
 	.meter_profile_delete  = nfp_mtr_profile_delete,
+	.meter_policy_add      = nfp_mtr_policy_add,
+	.meter_policy_delete   = nfp_mtr_policy_delete,
 };
 
 int
@@ -406,6 +578,7 @@ nfp_mtr_priv_init(struct nfp_pf_dev *pf_dev)
 	app_fw_flower->mtr_priv = priv;
 
 	LIST_INIT(&priv->profiles);
+	LIST_INIT(&priv->policies);
 
 	return 0;
 }
@@ -414,6 +587,7 @@ void
 nfp_mtr_priv_uninit(struct nfp_pf_dev *pf_dev)
 {
 	struct nfp_mtr_priv *priv;
+	struct nfp_mtr_policy *mtr_policy;
 	struct nfp_mtr_profile *mtr_profile;
 	struct nfp_app_fw_flower *app_fw_flower;
 
@@ -425,5 +599,10 @@ nfp_mtr_priv_uninit(struct nfp_pf_dev *pf_dev)
 		rte_free(mtr_profile);
 	}
 
+	LIST_FOREACH(mtr_policy, &priv->policies, next) {
+		LIST_REMOVE(mtr_policy, next);
+		rte_free(mtr_policy);
+	}
+
 	rte_free(priv);
 }
diff --git a/drivers/net/nfp/nfp_mtr.h b/drivers/net/nfp/nfp_mtr.h
index 05919c2bde..4fea0cf926 100644
--- a/drivers/net/nfp/nfp_mtr.h
+++ b/drivers/net/nfp/nfp_mtr.h
@@ -6,6 +6,8 @@
 #ifndef __NFP_MTR_H__
 #define __NFP_MTR_H__
 
+#include <rte_mtr.h>
+
 /**
  * The max meter count is determined by firmware.
  * The max count is 65536 defined by OF_METER_COUNT.
@@ -79,12 +81,28 @@ struct nfp_mtr_profile {
 	bool in_use;
 };
 
+/**
+ * Struct nfp_mtr_policy - meter policy information
+ * @next:        next meter policy object
+ * @policy_id:   meter policy id
+ * @ref_cnt:     reference count by meter
+ * @policy:      RTE_FLOW policy information
+ */
+struct nfp_mtr_policy {
+	LIST_ENTRY(nfp_mtr_policy) next;
+	uint32_t policy_id;
+	uint32_t ref_cnt;
+	struct rte_mtr_meter_policy_params policy;
+};
+
 /**
  * Struct nfp_mtr_priv - meter private data
  * @profiles:        the head node of profile list
+ * @policies:        the head node of policy list
  */
 struct nfp_mtr_priv {
 	LIST_HEAD(, nfp_mtr_profile) profiles;
+	LIST_HEAD(, nfp_mtr_policy) policies;
 };
 
 int nfp_net_mtr_ops_get(struct rte_eth_dev *dev, void *arg);
