diff --git a/drivers/net/sfc/sfc_flow.c b/drivers/net/sfc/sfc_flow.c
index f4d53bf770..3af95ac8ee 100644
--- a/drivers/net/sfc/sfc_flow.c
+++ b/drivers/net/sfc/sfc_flow.c
@@ -50,8 +50,8 @@ static const struct sfc_flow_ops_by_spec sfc_flow_ops_mae = {
 	.parse = sfc_flow_parse_rte_to_mae,
 	.verify = sfc_mae_flow_verify,
 	.cleanup = sfc_mae_flow_cleanup,
-	.insert = NULL,
-	.remove = NULL,
+	.insert = sfc_mae_flow_insert,
+	.remove = sfc_mae_flow_remove,
 };
 
 static const struct sfc_flow_ops_by_spec *
@@ -1202,6 +1202,7 @@ sfc_flow_parse_attr(struct sfc_adapter *sa,
 		spec_mae->priority = attr->priority;
 		spec_mae->match_spec = NULL;
 		spec_mae->action_set = NULL;
+		spec_mae->rule_id.id = EFX_MAE_RSRC_ID_INVALID;
 	}
 
 	return 0;
diff --git a/drivers/net/sfc/sfc_flow.h b/drivers/net/sfc/sfc_flow.h
index 7d15f47e60..d3bdbd5f75 100644
--- a/drivers/net/sfc/sfc_flow.h
+++ b/drivers/net/sfc/sfc_flow.h
@@ -67,6 +67,8 @@ struct sfc_flow_spec_mae {
 	efx_mae_match_spec_t		*match_spec;
 	/* Action set registry entry */
 	struct sfc_mae_action_set	*action_set;
+	/* Firmware-allocated rule ID */
+	efx_mae_rule_id_t		rule_id;
 };
 
 /* Flow specification */
diff --git a/drivers/net/sfc/sfc_mae.c b/drivers/net/sfc/sfc_mae.c
index 057eef537b..ea15ccaedb 100644
--- a/drivers/net/sfc/sfc_mae.c
+++ b/drivers/net/sfc/sfc_mae.c
@@ -113,6 +113,8 @@ sfc_mae_action_set_add(struct sfc_adapter *sa,
 	action_set->refcnt = 1;
 	action_set->spec = spec;
 
+	action_set->fw_rsrc.aset_id.id = EFX_MAE_RSRC_ID_INVALID;
+
 	TAILQ_INSERT_TAIL(&mae->action_sets, action_set, entries);
 
 	*action_setp = action_set;
@@ -134,11 +136,62 @@ sfc_mae_action_set_del(struct sfc_adapter *sa,
 	if (action_set->refcnt != 0)
 		return;
 
+	SFC_ASSERT(action_set->fw_rsrc.aset_id.id == EFX_MAE_RSRC_ID_INVALID);
+	SFC_ASSERT(action_set->fw_rsrc.refcnt == 0);
+
 	efx_mae_action_set_spec_fini(sa->nic, action_set->spec);
 	TAILQ_REMOVE(&mae->action_sets, action_set, entries);
 	rte_free(action_set);
 }
 
+static int
+sfc_mae_action_set_enable(struct sfc_adapter *sa,
+			  struct sfc_mae_action_set *action_set)
+{
+	struct sfc_mae_fw_rsrc *fw_rsrc = &action_set->fw_rsrc;
+	int rc;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+
+	if (fw_rsrc->refcnt == 0) {
+		SFC_ASSERT(fw_rsrc->aset_id.id == EFX_MAE_RSRC_ID_INVALID);
+		SFC_ASSERT(action_set->spec != NULL);
+
+		rc = efx_mae_action_set_alloc(sa->nic, action_set->spec,
+					      &fw_rsrc->aset_id);
+		if (rc != 0)
+			return rc;
+	}
+
+	++(fw_rsrc->refcnt);
+
+	return 0;
+}
+
+static int
+sfc_mae_action_set_disable(struct sfc_adapter *sa,
+			   struct sfc_mae_action_set *action_set)
+{
+	struct sfc_mae_fw_rsrc *fw_rsrc = &action_set->fw_rsrc;
+	int rc;
+
+	SFC_ASSERT(sfc_adapter_is_locked(sa));
+	SFC_ASSERT(fw_rsrc->aset_id.id != EFX_MAE_RSRC_ID_INVALID);
+	SFC_ASSERT(fw_rsrc->refcnt != 0);
+
+	if (fw_rsrc->refcnt == 1) {
+		rc = efx_mae_action_set_free(sa->nic, &fw_rsrc->aset_id);
+		if (rc != 0)
+			return rc;
+
+		fw_rsrc->aset_id.id = EFX_MAE_RSRC_ID_INVALID;
+	}
+
+	--(fw_rsrc->refcnt);
+
+	return 0;
+}
+
 void
 sfc_mae_flow_cleanup(struct sfc_adapter *sa,
 		     struct rte_flow *flow)
@@ -156,6 +209,8 @@ sfc_mae_flow_cleanup(struct sfc_adapter *sa,
 
 	spec_mae = &spec->mae;
 
+	SFC_ASSERT(spec_mae->rule_id.id == EFX_MAE_RSRC_ID_INVALID);
+
 	if (spec_mae->action_set != NULL)
 		sfc_mae_action_set_del(sa, spec_mae->action_set);
 
@@ -563,3 +618,56 @@ sfc_mae_flow_verify(struct sfc_adapter *sa,
 
 	return sfc_mae_action_rule_class_verify(sa, spec_mae);
 }
+
+int
+sfc_mae_flow_insert(struct sfc_adapter *sa,
+		    struct rte_flow *flow)
+{
+	struct sfc_flow_spec *spec = &flow->spec;
+	struct sfc_flow_spec_mae *spec_mae = &spec->mae;
+	struct sfc_mae_action_set *action_set = spec_mae->action_set;
+	struct sfc_mae_fw_rsrc *fw_rsrc = &action_set->fw_rsrc;
+	int rc;
+
+	SFC_ASSERT(spec_mae->rule_id.id == EFX_MAE_RSRC_ID_INVALID);
+	SFC_ASSERT(action_set != NULL);
+
+	rc = sfc_mae_action_set_enable(sa, action_set);
+	if (rc != 0)
+		goto fail_action_set_enable;
+
+	rc = efx_mae_action_rule_insert(sa->nic, spec_mae->match_spec,
+					NULL, &fw_rsrc->aset_id,
+					&spec_mae->rule_id);
+	if (rc != 0)
+		goto fail_action_rule_insert;
+
+	return 0;
+
+fail_action_rule_insert:
+	(void)sfc_mae_action_set_disable(sa, action_set);
+
+fail_action_set_enable:
+	return rc;
+}
+
+int
+sfc_mae_flow_remove(struct sfc_adapter *sa,
+		    struct rte_flow *flow)
+{
+	struct sfc_flow_spec *spec = &flow->spec;
+	struct sfc_flow_spec_mae *spec_mae = &spec->mae;
+	struct sfc_mae_action_set *action_set = spec_mae->action_set;
+	int rc;
+
+	SFC_ASSERT(spec_mae->rule_id.id != EFX_MAE_RSRC_ID_INVALID);
+	SFC_ASSERT(action_set != NULL);
+
+	rc = efx_mae_action_rule_remove(sa->nic, &spec_mae->rule_id);
+	if (rc != 0)
+		return rc;
+
+	spec_mae->rule_id.id = EFX_MAE_RSRC_ID_INVALID;
+
+	return sfc_mae_action_set_disable(sa, action_set);
+}
diff --git a/drivers/net/sfc/sfc_mae.h b/drivers/net/sfc/sfc_mae.h
index 1ef582e82b..d9f0ee3cbc 100644
--- a/drivers/net/sfc/sfc_mae.h
+++ b/drivers/net/sfc/sfc_mae.h
@@ -18,11 +18,21 @@
 extern "C" {
 #endif
 
+/** FW-allocatable resource context */
+struct sfc_mae_fw_rsrc {
+	unsigned int			refcnt;
+	RTE_STD_C11
+	union {
+		efx_mae_aset_id_t	aset_id;
+	};
+};
+
 /** Action set registry entry */
 struct sfc_mae_action_set {
 	TAILQ_ENTRY(sfc_mae_action_set)	entries;
 	unsigned int			refcnt;
 	efx_mae_actions_t		*spec;
+	struct sfc_mae_fw_rsrc		fw_rsrc;
 };
 
 TAILQ_HEAD(sfc_mae_action_sets, sfc_mae_action_set);
@@ -63,6 +73,8 @@ int sfc_mae_rule_parse_actions(struct sfc_adapter *sa,
 			       struct sfc_mae_action_set **action_setp,
 			       struct rte_flow_error *error);
 sfc_flow_verify_cb_t sfc_mae_flow_verify;
+sfc_flow_insert_cb_t sfc_mae_flow_insert;
+sfc_flow_remove_cb_t sfc_mae_flow_remove;
 
 #ifdef __cplusplus
 }
