diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index 86082208d0..634818cdf2 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -27,20 +27,30 @@
 
 struct sfc_flow_ops_by_spec {
 	sfc_flow_parse_cb_t	*parse;
+	sfc_flow_cleanup_cb_t	*cleanup;
 	sfc_flow_insert_cb_t	*insert;
 	sfc_flow_remove_cb_t	*remove;
 };
 
 static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_filter;
+static sfc_flow_parse_cb_t sfc_flow_parse_rte_to_mae;
 static sfc_flow_insert_cb_t sfc_flow_filter_insert;
 static sfc_flow_remove_cb_t sfc_flow_filter_remove;
 
 static const struct sfc_flow_ops_by_spec sfc_flow_ops_filter = {
 	.parse = sfc_flow_parse_rte_to_filter,
+	.cleanup = NULL,
 	.insert = sfc_flow_filter_insert,
 	.remove = sfc_flow_filter_remove,
 };
 
+static const struct sfc_flow_ops_by_spec sfc_flow_ops_mae = {
+	.parse = sfc_flow_parse_rte_to_mae,
+	.cleanup = sfc_mae_flow_cleanup,
+	.insert = NULL,
+	.remove = NULL,
+};
+
 static const struct sfc_flow_ops_by_spec *
 sfc_flow_get_ops_by_spec(struct rte_flow *flow)
 {
@@ -51,6 +61,9 @@ sfc_flow_get_ops_by_spec(struct rte_flow *flow)
 	case SFC_FLOW_SPEC_FILTER:
 		ops = &sfc_flow_ops_filter;
 		break;
+	case SFC_FLOW_SPEC_MAE:
+		ops = &sfc_flow_ops_mae;
+		break;
 	default:
 		SFC_ASSERT(false);
 		break;
@@ -1184,6 +1197,7 @@ sfc_flow_parse_attr(struct sfc_adapter *sa,
 		}
 		spec->type = SFC_FLOW_SPEC_MAE;
 		spec_mae->priority = attr->priority;
+		spec_mae->match_spec = NULL;
 	}
 
 	return 0;
@@ -2408,6 +2422,25 @@ sfc_flow_parse_rte_to_filter(struct rte_eth_dev *dev,
 	return rc;
 }
 
+static int
+sfc_flow_parse_rte_to_mae(struct rte_eth_dev *dev,
+			  const struct rte_flow_item pattern[],
+			  __rte_unused const struct rte_flow_action actions[],
+			  struct rte_flow *flow,
+			  struct rte_flow_error *error)
+{
+	struct sfc_adapter *sa = sfc_adapter_by_eth_dev(dev);
+	struct sfc_flow_spec *spec = &flow->spec;
+	struct sfc_flow_spec_mae *spec_mae = &spec->mae;
+	int rc;
+
+	rc = sfc_mae_rule_parse_pattern(sa, pattern, spec_mae, error);
+	if (rc != 0)
+		return rc;
+
+	return 0;
+}
+
 static int
 sfc_flow_parse(struct rte_eth_dev *dev,
 	       const struct rte_flow_attr *attr,
@@ -2451,8 +2484,14 @@ sfc_flow_zmalloc(struct rte_flow_error *error)
 }
 
 static void
-sfc_flow_free(__rte_unused struct sfc_adapter *sa, struct rte_flow *flow)
+sfc_flow_free(struct sfc_adapter *sa, struct rte_flow *flow)
 {
+	const struct sfc_flow_ops_by_spec *ops;
+
+	ops = sfc_flow_get_ops_by_spec(flow);
+	if (ops != NULL && ops->cleanup != NULL)
+		ops->cleanup(sa, flow);
+
 	rte_free(flow);
 }
 
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 1fbcb878d1..03a68d8633 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -63,6 +63,8 @@ struct sfc_flow_spec_filter {
 struct sfc_flow_spec_mae {
 	/* Desired priority level */
 	unsigned int			priority;
+	/* EFX match specification */
+	efx_mae_match_spec_t		*match_spec;
 };
 
 /* Flow specification */
@@ -100,6 +102,7 @@ enum sfc_flow_item_layers {
 /* Flow parse context types */
 enum sfc_flow_parse_ctx_type {
 	SFC_FLOW_PARSE_CTX_FILTER = 0,
+	SFC_FLOW_PARSE_CTX_MAE,
 
 	SFC_FLOW_PARSE_CTX_NTYPES
 };
@@ -112,6 +115,8 @@ struct sfc_flow_parse_ctx {
 	union {
 		/* Context pointer valid for filter-based (VNIC) flows */
 		efx_filter_spec_t *filter;
+		/* Context pointer valid for MAE-based flows */
+		struct sfc_mae_parse_ctx *mae;
 	};
 };
 
@@ -154,6 +159,9 @@ typedef int (sfc_flow_parse_cb_t)(struct rte_eth_dev *dev,
 				  struct rte_flow *flow,
 				  struct rte_flow_error *error);
 
+typedef void (sfc_flow_cleanup_cb_t)(struct sfc_adapter *sa,
+				     struct rte_flow *flow);
+
 typedef int (sfc_flow_insert_cb_t)(struct sfc_adapter *sa,
 				   struct rte_flow *flow);
 
diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index 487bd61f76..53e141775a 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -75,3 +75,68 @@ sfc_mae_detach(struct sfc_adapter *sa)
 
 	sfc_log_init(sa, "done");
 }
+
+void
+sfc_mae_flow_cleanup(struct sfc_adapter *sa,
+		     struct rte_flow *flow)
+{
+	struct sfc_flow_spec *spec;
+	struct sfc_flow_spec_mae *spec_mae;
+
+	if (flow == NULL)
+		return;
+
+	spec = &flow->spec;
+
+	if (spec == NULL)
+		return;
+
+	spec_mae = &spec->mae;
+
+	if (spec_mae->match_spec != NULL)
+		efx_mae_match_spec_fini(sa->nic, spec_mae->match_spec);
+}
+
+static const struct sfc_flow_item sfc_flow_items[] = {
+};
+
+int
+sfc_mae_rule_parse_pattern(struct sfc_adapter *sa,
+			   const struct rte_flow_item pattern[],
+			   struct sfc_flow_spec_mae *spec,
+			   struct rte_flow_error *error)
+{
+	struct sfc_mae_parse_ctx ctx_mae;
+	struct sfc_flow_parse_ctx ctx;
+	int rc;
+
+	memset(&ctx_mae, 0, sizeof(ctx_mae));
+
+	rc = efx_mae_match_spec_init(sa->nic, EFX_MAE_RULE_ACTION,
+				     spec->priority,
+				     &ctx_mae.match_spec_action);
+	if (rc != 0) {
+		rc = rte_flow_error_set(error, rc,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Failed to initialise action rule match specification");
+		goto fail_init_match_spec_action;
+	}
+
+	ctx.type = SFC_FLOW_PARSE_CTX_MAE;
+	ctx.mae = &ctx_mae;
+
+	rc = sfc_flow_parse_pattern(sfc_flow_items, RTE_DIM(sfc_flow_items),
+				    pattern, &ctx, error);
+	if (rc != 0)
+		goto fail_parse_pattern;
+
+	spec->match_spec = ctx_mae.match_spec_action;
+
+	return 0;
+
+fail_parse_pattern:
+	efx_mae_match_spec_fini(sa->nic, ctx_mae.match_spec_action);
+
+fail_init_match_spec_action:
+	return rc;
+}
diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h
index dd9ca07d15..536dadd092 100644
--- a/drivers/net/sfc/sfc_mae.h
+++ b/drivers/net/sfc/sfc_mae.h
@@ -33,9 +33,19 @@ struct sfc_mae {
 };
 
 struct sfc_adapter;
+struct sfc_flow_spec;
+
+struct sfc_mae_parse_ctx {
+	efx_mae_match_spec_t		*match_spec_action;
+};
 
 int sfc_mae_attach(struct sfc_adapter *sa);
 void sfc_mae_detach(struct sfc_adapter *sa);
+sfc_flow_cleanup_cb_t sfc_mae_flow_cleanup;
+int sfc_mae_rule_parse_pattern(struct sfc_adapter *sa,
+			       const struct rte_flow_item pattern[],
+			       struct sfc_flow_spec_mae *spec,
+			       struct rte_flow_error *error);
 
 #ifdef __cplusplus
 }
