diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 72b1e35673..f0988712df 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -686,10 +686,14 @@ mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
 			for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
 				aso_mtr = &mtr_pool->mtrs[i];
-				if (aso_mtr->fm.meter_action)
+				if (aso_mtr->fm.meter_action_g)
 					claim_zero
 					(mlx5_glue->destroy_flow_action
-					(aso_mtr->fm.meter_action));
+					(aso_mtr->fm.meter_action_g));
+				if (aso_mtr->fm.meter_action_y)
+					claim_zero
+					(mlx5_glue->destroy_flow_action
+					(aso_mtr->fm.meter_action_y));
 			}
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
 			claim_zero(mlx5_devx_cmd_destroy
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index c92ce6b527..ef755ee8cf 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -869,8 +869,10 @@ struct mlx5_flow_meter_info {
 	/**< Use count. */
 	struct mlx5_indexed_pool *flow_ipool;
 	/**< Index pool for flow id. */
-	void *meter_action;
+	void *meter_action_g;
 	/**< Flow meter action. */
+	void *meter_action_y;
+	/**< Flow meter action for yellow init_color. */
 };
 
 /* PPS(packets per second) map to BPS(Bytes per second).
@@ -1873,6 +1875,10 @@ struct mlx5_flow_meter_policy *mlx5_flow_meter_policy_find
 		(struct rte_eth_dev *dev,
 		uint32_t policy_id,
 		uint32_t *policy_idx);
+struct mlx5_flow_meter_info *
+mlx5_flow_meter_hierarchy_next_meter(struct mlx5_priv *priv,
+				     struct mlx5_flow_meter_policy *policy,
+				     uint32_t *mtr_idx);
 struct mlx5_flow_meter_policy *
 mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
 					struct mlx5_flow_meter_policy *policy);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index f9c56204c4..ee7a32acc8 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -6534,13 +6534,13 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 			struct mlx5_aso_mtr_pool,
 			mtrs[mtr_free->offset]);
 	mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
-	if (!mtr_free->fm.meter_action) {
+	if (!mtr_free->fm.meter_action_g) {
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
 		struct rte_flow_error error;
 		uint8_t reg_id;
 
 		reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
-		mtr_free->fm.meter_action =
+		mtr_free->fm.meter_action_g =
 			mlx5_glue->dv_create_flow_action_aso
 						(priv->sh->rx_domain,
 						 pool->devx_obj->obj,
@@ -6548,7 +6548,7 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 						 (1 << MLX5_FLOW_COLOR_GREEN),
 						 reg_id - REG_C_0);
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
-		if (!mtr_free->fm.meter_action) {
+		if (!mtr_free->fm.meter_action_g) {
 			flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
 			return 0;
 		}
@@ -13401,7 +13401,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
 					NULL, "Failed to get meter in flow.");
 			/* Set the meter action. */
 			dev_flow->dv.actions[actions_n++] =
-				wks->fm->meter_action;
+				wks->fm->meter_action_g;
 			action_flags |= MLX5_FLOW_ACTION_METER;
 			break;
 		case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
@@ -15427,7 +15427,7 @@ __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
 
 	for (i = 0; i < RTE_COLORS; i++) {
 		next_fm = NULL;
-		if (i == RTE_COLOR_GREEN && policy &&
+		if (i <= RTE_COLOR_YELLOW && policy &&
 		    policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
 			next_fm = mlx5_flow_meter_find(priv,
 					policy->act_cnt[i].next_mtr_id, NULL);
@@ -15551,6 +15551,51 @@ flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
 		mtr_policy->dr_drop_action[j] = NULL;
 }
 
+/**
+ * Create yellow action for color aware meter.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] fm
+ *   Meter information table.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+__flow_dv_create_mtr_yellow_action(struct rte_eth_dev *dev,
+				   struct mlx5_flow_meter_info *fm,
+				   struct rte_mtr_error *error)
+{
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_error flow_err;
+	struct mlx5_aso_mtr *aso_mtr;
+	struct mlx5_aso_mtr_pool *pool;
+	uint8_t reg_id;
+
+	aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+	pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool, mtrs[aso_mtr->offset]);
+	reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
+	fm->meter_action_y =
+		mlx5_glue->dv_create_flow_action_aso(priv->sh->rx_domain,
+						     pool->devx_obj->obj,
+						     aso_mtr->offset,
+						     (1 << MLX5_FLOW_COLOR_YELLOW),
+						     reg_id - REG_C_0);
+#else
+	RTE_SET_USED(dev);
+#endif
+	if (!fm->meter_action_y) {
+		return -rte_mtr_error_set(error, EINVAL, RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+					  "Fail to create yellow meter action.");
+	}
+	return 0;
+}
+
 /**
  * Create policy action per domain, lock free,
  * (mutex should be acquired by caller).
@@ -15870,7 +15915,7 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
 				break;
 			}
 			/*
-			 * No need to check meter hierarchy for Y or R colors
+			 * No need to check meter hierarchy for R colors
 			 * here since it is done in the validation stage.
 			 */
 			case RTE_FLOW_ACTION_TYPE_METER:
@@ -15921,6 +15966,10 @@ __flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
 					action_flags |=
 						MLX5_FLOW_ACTION_SET_TAG;
 				}
+				if (i == RTE_COLOR_YELLOW && next_fm->color_aware &&
+				    !next_fm->meter_action_y)
+					if (__flow_dv_create_mtr_yellow_action(dev, next_fm, error))
+						return -rte_errno;
 				act_cnt->fate_action = MLX5_FLOW_FATE_MTR;
 				act_cnt->next_mtr_id = next_fm->meter_id;
 				act_cnt->next_sub_policy = NULL;
@@ -16519,7 +16568,7 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
 	struct mlx5_flow_dv_tag_resource *tag;
 	struct mlx5_flow_dv_port_id_action_resource *port_action;
 	struct mlx5_hrxq *hrxq;
-	struct mlx5_flow_meter_info *next_fm = NULL;
+	struct mlx5_flow_meter_info *next_fm[RTE_COLORS] = {NULL};
 	struct mlx5_flow_meter_policy *next_policy;
 	struct mlx5_flow_meter_sub_policy *next_sub_policy;
 	struct mlx5_flow_tbl_data_entry *tbl_data;
@@ -16540,30 +16589,31 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
 			acts[i].actions_n = 1;
 			continue;
 		}
-		if (i == RTE_COLOR_GREEN &&
-		    mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
+		if (mtr_policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR) {
 			struct rte_flow_attr attr = {
 				.transfer = transfer
 			};
 
-			next_fm = mlx5_flow_meter_find(priv,
+			next_fm[i] = mlx5_flow_meter_find(priv,
 					mtr_policy->act_cnt[i].next_mtr_id,
 					NULL);
-			if (!next_fm) {
+			if (!next_fm[i]) {
 				DRV_LOG(ERR,
 					"Failed to get next hierarchy meter.");
 				goto err_exit;
 			}
-			if (mlx5_flow_meter_attach(priv, next_fm,
+			if (mlx5_flow_meter_attach(priv, next_fm[i],
 						   &attr, &error)) {
 				DRV_LOG(ERR, "%s", error.message);
-				next_fm = NULL;
+				next_fm[i] = NULL;
 				goto err_exit;
 			}
 			/* Meter action must be the first for TX. */
 			if (mtr_first) {
 				acts[i].dv_actions[acts[i].actions_n] =
-					next_fm->meter_action;
+					(next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ?
+						next_fm[i]->meter_action_y :
+						next_fm[i]->meter_action_g;
 				acts[i].actions_n++;
 			}
 		}
@@ -16621,14 +16671,16 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
 				acts[i].actions_n++;
 				break;
 			case MLX5_FLOW_FATE_MTR:
-				if (!next_fm) {
+				if (!next_fm[i]) {
 					DRV_LOG(ERR,
 						"No next hierarchy meter.");
 					goto err_exit;
 				}
 				if (!mtr_first) {
 					acts[i].dv_actions[acts[i].actions_n] =
-							next_fm->meter_action;
+						(next_fm[i]->color_aware && i == RTE_COLOR_YELLOW) ?
+							next_fm[i]->meter_action_y :
+							next_fm[i]->meter_action_g;
 					acts[i].actions_n++;
 				}
 				if (mtr_policy->act_cnt[i].next_sub_policy) {
@@ -16637,7 +16689,7 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
 				} else {
 					next_policy =
 						mlx5_flow_meter_policy_find(dev,
-						next_fm->policy_id, NULL);
+								next_fm[i]->policy_id, NULL);
 					MLX5_ASSERT(next_policy);
 					next_sub_policy =
 					next_policy->sub_policys[domain][0];
@@ -16664,8 +16716,9 @@ __flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
 	}
 	return 0;
 err_exit:
-	if (next_fm)
-		mlx5_flow_meter_detach(priv, next_fm);
+	for (i = 0; i < RTE_COLORS; i++)
+		if (next_fm[i])
+			mlx5_flow_meter_detach(priv, next_fm[i]);
 	return -1;
 }
 
@@ -17181,8 +17234,9 @@ flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
 			DRV_LOG(ERR, "Exceed max meter number in hierarchy.");
 			return NULL;
 		}
-		next_fm = mlx5_flow_meter_find(priv,
-			mtr_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
+		rte_spinlock_lock(&mtr_policy->sl);
+		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, mtr_policy, NULL);
+		rte_spinlock_unlock(&mtr_policy->sl);
 		if (!next_fm) {
 			DRV_LOG(ERR, "Failed to get next meter in hierarchy.");
 			return NULL;
@@ -17330,11 +17384,11 @@ flow_dv_meter_hierarchy_rule_create(struct rte_eth_dev *dev,
 					struct mlx5_flow_tbl_data_entry, tbl);
 		act_cnt = &mtr_policy->act_cnt[i];
 		if (mtr_first) {
-			acts.dv_actions[0] = next_fm->meter_action;
+			acts.dv_actions[0] = next_fm->meter_action_g;
 			acts.dv_actions[1] = act_cnt->modify_hdr->action;
 		} else {
 			acts.dv_actions[0] = act_cnt->modify_hdr->action;
-			acts.dv_actions[1] = next_fm->meter_action;
+			acts.dv_actions[1] = next_fm->meter_action_g;
 		}
 		acts.dv_actions[2] = tbl_data->jump.action;
 		acts.actions_n = 3;
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index b52de70afa..22f6ca7faf 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -611,6 +611,36 @@ mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
 	return NULL;
 }
 
+/**
+ * Get the next meter from one meter's policy in hierarchy chain.
+ * Lock free, mutex should be acquired by caller.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5_priv.
+ * @param[in] policy
+ *   Pointer to flow meter policy.
+ * @param[out] mtr_idx
+ *   Pointer to Meter index.
+ *
+ * @return
+ *   Pointer to the next meter, or NULL when fail.
+ */
+struct mlx5_flow_meter_info *
+mlx5_flow_meter_hierarchy_next_meter(struct mlx5_priv *priv,
+				     struct mlx5_flow_meter_policy *policy,
+				     uint32_t *mtr_idx)
+{
+	int i;
+
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
+			return mlx5_flow_meter_find(priv,
+						    policy->act_cnt[i].next_mtr_id,
+						    mtr_idx);
+	}
+	return NULL;
+}
+
 /**
  * Get the last meter's policy from one meter's policy in hierarchy.
  *
@@ -631,8 +661,9 @@ mlx5_flow_meter_hierarchy_get_final_policy(struct rte_eth_dev *dev,
 	struct mlx5_flow_meter_policy *next_policy = policy;
 
 	while (next_policy->is_hierarchy) {
-		next_fm = mlx5_flow_meter_find(priv,
-		       next_policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id, NULL);
+		rte_spinlock_lock(&next_policy->sl);
+		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, next_policy, NULL);
+		rte_spinlock_unlock(&next_policy->sl);
 		if (!next_fm || next_fm->def_policy)
 			return NULL;
 		next_policy = mlx5_flow_meter_policy_find(dev,
@@ -1105,9 +1136,9 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 				ebs_mantissa, val);
 		}
 		/* Apply modifications to meter only if it was created. */
-		if (fm->meter_action) {
+		if (fm->meter_action_g) {
 			ret = mlx5_glue->dv_modify_flow_action_meter
-					(fm->meter_action, &mod_attr,
+					(fm->meter_action_g, &mod_attr,
 					rte_cpu_to_be_64(modify_bits));
 			if (ret)
 				return ret;
@@ -1908,7 +1939,7 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv,
 		rte_spinlock_unlock(&fm->sl);
 	} else {
 		rte_spinlock_lock(&fm->sl);
-		if (fm->meter_action) {
+		if (fm->meter_action_g) {
 			if (fm->shared &&
 			    attr->transfer == fm->transfer &&
 			    attr->ingress == fm->ingress &&
@@ -1928,9 +1959,9 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv,
 			fm->transfer = attr->transfer;
 			fm->ref_cnt = 1;
 			/* This also creates the meter object. */
-			fm->meter_action = mlx5_flow_meter_action_create(priv,
+			fm->meter_action_g = mlx5_flow_meter_action_create(priv,
 									 fm);
-			if (!fm->meter_action) {
+			if (!fm->meter_action_g) {
 				fm->ref_cnt = 0;
 				fm->ingress = 0;
 				fm->egress = 0;
@@ -1962,8 +1993,8 @@ mlx5_flow_meter_detach(struct mlx5_priv *priv,
 	rte_spinlock_lock(&fm->sl);
 	MLX5_ASSERT(fm->ref_cnt);
 	if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
-		mlx5_glue->destroy_flow_action(fm->meter_action);
-		fm->meter_action = NULL;
+		mlx5_glue->destroy_flow_action(fm->meter_action_g);
+		fm->meter_action_g = NULL;
 		fm->ingress = 0;
 		fm->egress = 0;
 		fm->transfer = 0;
@@ -2040,9 +2071,7 @@ mlx5_flow_meter_flush_hierarchy(struct rte_eth_dev *dev,
 	MLX5_ASSERT(policy);
 	while (!fm->ref_cnt && policy->is_hierarchy) {
 		policy_id = fm->policy_id;
-		next_fm = mlx5_flow_meter_find(priv,
-				policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
-				&next_mtr_idx);
+		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &next_mtr_idx);
 		if (next_fm) {
 			next_policy = mlx5_flow_meter_policy_find(dev,
 							next_fm->policy_id,
@@ -2120,9 +2149,7 @@ mlx5_flow_meter_flush_all_hierarchies(struct rte_eth_dev *dev,
 		policy = sub_policy->main_policy;
 		if (!policy || !policy->is_hierarchy || policy->ref_cnt)
 			continue;
-		next_fm = mlx5_flow_meter_find(priv,
-				policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
-				&mtr_idx);
+		next_fm = mlx5_flow_meter_hierarchy_next_meter(priv, policy, &mtr_idx);
 		if (__mlx5_flow_meter_policy_delete(dev, i, policy,
 						    error, true))
 			return -rte_mtr_error_set(error,
