diff --git a/lib/pipeline/rte_swx_ctl.c b/lib/pipeline/rte_swx_ctl.c
index 86b58e2..1c908e3 100644
--- a/lib/pipeline/rte_swx_ctl.c
+++ b/lib/pipeline/rte_swx_ctl.c
@@ -1446,6 +1446,8 @@ struct rte_swx_ctl_pipeline *
 	CHECK(entry, EINVAL);
 	CHECK(!table_entry_check(ctl, table_id, entry, 1, 1), EINVAL);
 
+	CHECK(table->actions[entry->action_id].action_is_for_table_entries, EINVAL);
+
 	new_entry = table_entry_duplicate(ctl, table_id, entry, 1, 1);
 	CHECK(new_entry, ENOMEM);
 
@@ -1651,6 +1653,8 @@ struct rte_swx_ctl_pipeline *
 	CHECK(entry, EINVAL);
 	CHECK(!table_entry_check(ctl, table_id, entry, 0, 1), EINVAL);
 
+	CHECK(table->actions[entry->action_id].action_is_for_default_entry, EINVAL);
+
 	new_entry = table_entry_duplicate(ctl, table_id, entry, 0, 1);
 	CHECK(new_entry, ENOMEM);
 
@@ -2378,6 +2382,8 @@ struct rte_swx_ctl_pipeline *
 	CHECK(entry, EINVAL);
 	CHECK(!learner_default_entry_check(ctl, learner_id, entry), EINVAL);
 
+	CHECK(l->actions[entry->action_id].action_is_for_default_entry, EINVAL);
+
 	new_entry = learner_default_entry_duplicate(ctl, learner_id, entry);
 	CHECK(new_entry, ENOMEM);
 
diff --git a/lib/pipeline/rte_swx_ctl.h b/lib/pipeline/rte_swx_ctl.h
index 8075972..46d0582 100644
--- a/lib/pipeline/rte_swx_ctl.h
+++ b/lib/pipeline/rte_swx_ctl.h
@@ -301,6 +301,12 @@ struct rte_swx_ctl_table_match_field_info {
 struct rte_swx_ctl_table_action_info {
 	/** Action ID. */
 	uint32_t action_id;
+
+	/**  When non-zero (true), the action can be assigned to regular table entries. */
+	int action_is_for_table_entries;
+
+	/**  When non-zero (true), the action can be assigned to the table default entry. */
+	int action_is_for_default_entry;
 };
 
 /**
diff --git a/lib/pipeline/rte_swx_pipeline.c b/lib/pipeline/rte_swx_pipeline.c
index 1cd09a4..f96d6ba 100644
--- a/lib/pipeline/rte_swx_pipeline.c
+++ b/lib/pipeline/rte_swx_pipeline.c
@@ -7309,7 +7309,7 @@ struct_field_parse(struct rte_swx_pipeline *p,
 			      uint32_t size)
 {
 	struct table_type *type;
-	struct table *t;
+	struct table *t = NULL;
 	struct action *default_action;
 	struct header *header = NULL;
 	uint32_t action_data_size_max = 0, i;
@@ -7336,6 +7336,7 @@ struct_field_parse(struct rte_swx_pipeline *p,
 		const char *action_name = params->action_names[i];
 		struct action *a;
 		uint32_t action_data_size;
+		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
 
 		CHECK_NAME(action_name, EINVAL);
 
@@ -7346,6 +7347,12 @@ struct_field_parse(struct rte_swx_pipeline *p,
 		action_data_size = a->st ? a->st->n_bits / 8 : 0;
 		if (action_data_size > action_data_size_max)
 			action_data_size_max = action_data_size;
+
+		if (params->action_is_for_table_entries)
+			action_is_for_table_entries = params->action_is_for_table_entries[i];
+		if (params->action_is_for_default_entry)
+			action_is_for_default_entry = params->action_is_for_default_entry[i];
+		CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL);
 	}
 
 	CHECK_NAME(params->default_action_name, EINVAL);
@@ -7354,6 +7361,9 @@ struct_field_parse(struct rte_swx_pipeline *p,
 			    params->default_action_name))
 			break;
 	CHECK(i < params->n_actions, EINVAL);
+	CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i],
+	      EINVAL);
+
 	default_action = action_find(p, params->default_action_name);
 	CHECK((default_action->st && params->default_action_data) ||
 	      !params->default_action_data, EINVAL);
@@ -7380,28 +7390,27 @@ struct_field_parse(struct rte_swx_pipeline *p,
 	CHECK(t, ENOMEM);
 
 	t->fields = calloc(params->n_fields, sizeof(struct match_field));
-	if (!t->fields) {
-		free(t);
-		CHECK(0, ENOMEM);
-	}
+	if (!t->fields)
+		goto nomem;
 
 	t->actions = calloc(params->n_actions, sizeof(struct action *));
-	if (!t->actions) {
-		free(t->fields);
-		free(t);
-		CHECK(0, ENOMEM);
-	}
+	if (!t->actions)
+		goto nomem;
 
 	if (action_data_size_max) {
 		t->default_action_data = calloc(1, action_data_size_max);
-		if (!t->default_action_data) {
-			free(t->actions);
-			free(t->fields);
-			free(t);
-			CHECK(0, ENOMEM);
-		}
+		if (!t->default_action_data)
+			goto nomem;
 	}
 
+	t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
+	if(!t->action_is_for_table_entries)
+		goto nomem;
+
+	t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
+	if(!t->action_is_for_default_entry)
+		goto nomem;
+
 	/* Node initialization. */
 	strcpy(t->name, name);
 	if (args && args[0])
@@ -7420,8 +7429,18 @@ struct_field_parse(struct rte_swx_pipeline *p,
 	t->n_fields = params->n_fields;
 	t->header = header;
 
-	for (i = 0; i < params->n_actions; i++)
+	for (i = 0; i < params->n_actions; i++) {
+		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
+
+		if (params->action_is_for_table_entries)
+			action_is_for_table_entries = params->action_is_for_table_entries[i];
+		if (params->action_is_for_default_entry)
+			action_is_for_default_entry = params->action_is_for_default_entry[i];
+
 		t->actions[i] = action_find(p, params->action_names[i]);
+		t->action_is_for_table_entries[i] = action_is_for_table_entries;
+		t->action_is_for_default_entry[i] = action_is_for_default_entry;
+	}
 	t->default_action = default_action;
 	if (default_action->st)
 		memcpy(t->default_action_data,
@@ -7439,6 +7458,19 @@ struct_field_parse(struct rte_swx_pipeline *p,
 	p->n_tables++;
 
 	return 0;
+
+nomem:
+	if (!t)
+		return -ENOMEM;
+
+	free(t->action_is_for_default_entry);
+	free(t->action_is_for_table_entries);
+	free(t->default_action_data);
+	free(t->actions);
+	free(t->fields);
+	free(t);
+
+	return -ENOMEM;
 }
 
 static struct rte_swx_table_params *
@@ -8179,12 +8211,12 @@ struct_field_parse(struct rte_swx_pipeline *p,
 
 	/* Action checks. */
 	CHECK(params->n_actions, EINVAL);
-
 	CHECK(params->action_names, EINVAL);
 	for (i = 0; i < params->n_actions; i++) {
 		const char *action_name = params->action_names[i];
 		struct action *a;
 		uint32_t action_data_size;
+		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
 
 		CHECK_NAME(action_name, EINVAL);
 
@@ -8201,6 +8233,12 @@ struct_field_parse(struct rte_swx_pipeline *p,
 		action_data_size = a->st ? a->st->n_bits / 8 : 0;
 		if (action_data_size > action_data_size_max)
 			action_data_size_max = action_data_size;
+
+		if (params->action_is_for_table_entries)
+			action_is_for_table_entries = params->action_is_for_table_entries[i];
+		if (params->action_is_for_default_entry)
+			action_is_for_default_entry = params->action_is_for_default_entry[i];
+		CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL);
 	}
 
 	CHECK_NAME(params->default_action_name, EINVAL);
@@ -8209,6 +8247,8 @@ struct_field_parse(struct rte_swx_pipeline *p,
 			    params->default_action_name))
 			break;
 	CHECK(i < params->n_actions, EINVAL);
+	CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i],
+	      EINVAL);
 
 	default_action = action_find(p, params->default_action_name);
 	CHECK((default_action->st && params->default_action_data) ||
@@ -8237,6 +8277,14 @@ struct_field_parse(struct rte_swx_pipeline *p,
 			goto nomem;
 	}
 
+	l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
+	if (!l->action_is_for_table_entries)
+		goto nomem;
+
+	l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
+	if (!l->action_is_for_default_entry)
+		goto nomem;
+
 	/* Node initialization. */
 	strcpy(l->name, name);
 
@@ -8252,8 +8300,18 @@ struct_field_parse(struct rte_swx_pipeline *p,
 
 	l->header = header;
 
-	for (i = 0; i < params->n_actions; i++)
+	for (i = 0; i < params->n_actions; i++) {
+		int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
+
+		if (params->action_is_for_table_entries)
+			action_is_for_table_entries = params->action_is_for_table_entries[i];
+		if (params->action_is_for_default_entry)
+			action_is_for_default_entry = params->action_is_for_default_entry[i];
+
 		l->actions[i] = action_find(p, params->action_names[i]);
+		l->action_is_for_table_entries[i] = action_is_for_table_entries;
+		l->action_is_for_default_entry[i] = action_is_for_default_entry;
+	}
 
 	l->default_action = default_action;
 
@@ -8284,6 +8342,9 @@ struct_field_parse(struct rte_swx_pipeline *p,
 	if (!l)
 		return -ENOMEM;
 
+	free(l->action_is_for_default_entry);
+	free(l->action_is_for_table_entries);
+	free(l->default_action_data);
 	free(l->actions);
 	free(l->fields);
 	free(l);
@@ -9277,6 +9338,9 @@ struct meter_profile meter_profile_default = {
 
 	table_action->action_id = t->actions[table_action_id]->id;
 
+	table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id];
+	table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id];
+
 	return 0;
 }
 
@@ -9464,6 +9528,9 @@ struct meter_profile meter_profile_default = {
 
 	learner_action->action_id = l->actions[learner_action_id]->id;
 
+	learner_action->action_is_for_table_entries = l->action_is_for_table_entries[learner_action_id];
+	learner_action->action_is_for_default_entry = l->action_is_for_default_entry[learner_action_id];
+
 	return 0;
 }
 
diff --git a/lib/pipeline/rte_swx_pipeline.h b/lib/pipeline/rte_swx_pipeline.h
index 490ff60..9c3d081 100644
--- a/lib/pipeline/rte_swx_pipeline.h
+++ b/lib/pipeline/rte_swx_pipeline.h
@@ -567,6 +567,20 @@ struct rte_swx_pipeline_table_params {
 	/** The set of actions for the current table. */
 	const char **action_names;
 
+	/**  Array of *n_actions* flags. For each action, the associated flag
+	 * indicates whether the action can be assigned to regular table entries
+	 * (when non-zero, i.e. true) or not (when zero, i.e. false). When set
+	 * to NULL, it defaults to true for all actions.
+	 */
+	int *action_is_for_table_entries;
+
+	/**  Array of *n_actions* flags. For each action, the associated flag
+	 * indicates whether the action can be assigned to the default table
+	 * entry (when non-zero, i.e. true) or not (when zero, i.e. false).
+	 * When set to NULL, it defaults to true for all actions.
+	 */
+	int *action_is_for_default_entry;
+
 	/** The number of actions for the current table. Must be at least one.
 	 */
 	uint32_t n_actions;
@@ -692,6 +706,20 @@ struct rte_swx_pipeline_learner_params {
 	/** The set of actions for the current table. */
 	const char **action_names;
 
+	/**  Array of *n_actions* flags. For each action, the associated flag
+	 * indicates whether the action can be assigned to regular table entries
+	 * (when non-zero, i.e. true) or not (when zero, i.e. false). When set
+	 * to NULL, it defaults to true for all actions.
+	 */
+	int *action_is_for_table_entries;
+
+	/**  Array of *n_actions* flags. For each action, the associated flag
+	 * indicates whether the action can be assigned to the default table
+	 * entry (when non-zero, i.e. true) or not (when zero, i.e. false).
+	 * When set to NULL, it defaults to true for all actions.
+	 */
+	int *action_is_for_default_entry;
+
 	/** The number of actions for the current table. Must be at least one.
 	 */
 	uint32_t n_actions;
diff --git a/lib/pipeline/rte_swx_pipeline_internal.h b/lib/pipeline/rte_swx_pipeline_internal.h
index 4361c53..1921fdc 100644
--- a/lib/pipeline/rte_swx_pipeline_internal.h
+++ b/lib/pipeline/rte_swx_pipeline_internal.h
@@ -746,6 +746,8 @@ struct table {
 	uint32_t n_actions;
 	int default_action_is_const;
 	uint32_t action_data_size_max;
+	int *action_is_for_table_entries;
+	int *action_is_for_default_entry;
 
 	uint32_t size;
 	uint32_t id;
@@ -815,6 +817,8 @@ struct learner {
 	uint32_t n_actions;
 	int default_action_is_const;
 	uint32_t action_data_size_max;
+	int *action_is_for_table_entries;
+	int *action_is_for_default_entry;
 
 	uint32_t size;
 	uint32_t timeout;
diff --git a/lib/pipeline/rte_swx_pipeline_spec.c b/lib/pipeline/rte_swx_pipeline_spec.c
index 5c21a7a..8e9aa44 100644
--- a/lib/pipeline/rte_swx_pipeline_spec.c
+++ b/lib/pipeline/rte_swx_pipeline_spec.c
@@ -539,7 +539,7 @@ struct action_spec {
  *		...
  *	}
  *	actions {
- *		ACTION_NAME
+ *		ACTION_NAME [ @tableonly | @defaultonly ]
  *		...
  *	}
  *	default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
@@ -597,6 +597,12 @@ struct table_spec {
 	free(s->params.default_action_data);
 	s->params.default_action_data = NULL;
 
+	free(s->params.action_is_for_table_entries);
+	s->params.action_is_for_table_entries = NULL;
+
+	free(s->params.action_is_for_default_entry);
+	s->params.action_is_for_default_entry = NULL;
+
 	s->params.default_action_is_const = 0;
 
 	free(s->recommended_table_type_name);
@@ -730,8 +736,10 @@ struct table_spec {
 			  uint32_t *err_line,
 			  const char **err_msg)
 {
-	const char **new_action_names;
-	char *name;
+	const char **new_action_names = NULL;
+	int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
+	char *name = NULL;
+	int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
 
 	/* Handle end of block. */
 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
@@ -740,7 +748,9 @@ struct table_spec {
 	}
 
 	/* Check input arguments. */
-	if (n_tokens != 1) {
+	if ((n_tokens > 2) ||
+	    ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
+	      strcmp(tokens[1], "@defaultonly"))) {
 		if (err_line)
 			*err_line = n_lines;
 		if (err_msg)
@@ -749,18 +759,30 @@ struct table_spec {
 	}
 
 	name = strdup(tokens[0]);
-	if (!name) {
-		if (err_line)
-			*err_line = n_lines;
-		if (err_msg)
-			*err_msg = "Memory allocation failed.";
-		return -ENOMEM;
+
+	if (n_tokens == 2) {
+		if (!strcmp(tokens[1], "@tableonly"))
+			action_is_for_default_entry = 0;
+
+		if (!strcmp(tokens[1], "@defaultonly"))
+			action_is_for_table_entries = 0;
 	}
 
 	new_action_names = realloc(s->params.action_names,
 				   (s->params.n_actions + 1) * sizeof(char *));
-	if (!new_action_names) {
+	new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
+						  (s->params.n_actions + 1) * sizeof(int));
+	new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
+						  (s->params.n_actions + 1) * sizeof(int));
+
+	if (!name ||
+	    !new_action_names ||
+	    !new_action_is_for_table_entries ||
+	    !new_action_is_for_default_entry) {
 		free(name);
+		free(new_action_names);
+		free(new_action_is_for_table_entries);
+		free(new_action_is_for_default_entry);
 
 		if (err_line)
 			*err_line = n_lines;
@@ -771,6 +793,13 @@ struct table_spec {
 
 	s->params.action_names = new_action_names;
 	s->params.action_names[s->params.n_actions] = name;
+
+	s->params.action_is_for_table_entries = new_action_is_for_table_entries;
+	s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
+
+	s->params.action_is_for_default_entry = new_action_is_for_default_entry;
+	s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
+
 	s->params.n_actions++;
 
 	return 0;
@@ -1293,7 +1322,7 @@ struct selector_spec {
  *		...
  *	}
  *	actions {
- *		ACTION_NAME
+ *		ACTION_NAME [ @tableonly | @defaultonly]
  *		...
  *	}
  *	default_action ACTION_NAME args none | ARGS_BYTE_ARRAY [ const ]
@@ -1349,6 +1378,12 @@ struct learner_spec {
 	free(s->params.default_action_data);
 	s->params.default_action_data = NULL;
 
+	free(s->params.action_is_for_table_entries);
+	s->params.action_is_for_table_entries = NULL;
+
+	free(s->params.action_is_for_default_entry);
+	s->params.action_is_for_default_entry = NULL;
+
 	s->params.default_action_is_const = 0;
 
 	s->size = 0;
@@ -1459,7 +1494,9 @@ struct learner_spec {
 			    const char **err_msg)
 {
 	const char **new_action_names = NULL;
-	char *action_name = NULL;
+	int *new_action_is_for_table_entries = NULL, *new_action_is_for_default_entry = NULL;
+	char *name = NULL;
+	int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
 
 	/* Handle end of block. */
 	if ((n_tokens == 1) && !strcmp(tokens[0], "}")) {
@@ -1468,7 +1505,9 @@ struct learner_spec {
 	}
 
 	/* Check input arguments. */
-	if (n_tokens != 1) {
+	if ((n_tokens > 2) ||
+	    ((n_tokens == 2) && strcmp(tokens[1], "@tableonly") &&
+	      strcmp(tokens[1], "@defaultonly"))) {
 		if (err_line)
 			*err_line = n_lines;
 		if (err_msg)
@@ -1476,14 +1515,31 @@ struct learner_spec {
 		return -EINVAL;
 	}
 
-	action_name = strdup(tokens[0]);
+	name = strdup(tokens[0]);
+
+	if (n_tokens == 2) {
+		if (!strcmp(tokens[1], "@tableonly"))
+			action_is_for_default_entry = 0;
+
+		if (!strcmp(tokens[1], "@defaultonly"))
+			action_is_for_table_entries = 0;
+	}
 
 	new_action_names = realloc(s->params.action_names,
 				   (s->params.n_actions + 1) * sizeof(char *));
-
-	if (!action_name || !new_action_names) {
-		free(action_name);
+	new_action_is_for_table_entries = realloc(s->params.action_is_for_table_entries,
+						  (s->params.n_actions + 1) * sizeof(int));
+	new_action_is_for_default_entry = realloc(s->params.action_is_for_default_entry,
+						  (s->params.n_actions + 1) * sizeof(int));
+
+	if (!name ||
+	    !new_action_names ||
+	    !new_action_is_for_table_entries ||
+	    !new_action_is_for_default_entry) {
+		free(name);
 		free(new_action_names);
+		free(new_action_is_for_table_entries);
+		free(new_action_is_for_default_entry);
 
 		if (err_line)
 			*err_line = n_lines;
@@ -1493,7 +1549,14 @@ struct learner_spec {
 	}
 
 	s->params.action_names = new_action_names;
-	s->params.action_names[s->params.n_actions] = action_name;
+	s->params.action_names[s->params.n_actions] = name;
+
+	s->params.action_is_for_table_entries = new_action_is_for_table_entries;
+	s->params.action_is_for_table_entries[s->params.n_actions] = action_is_for_table_entries;
+
+	s->params.action_is_for_default_entry = new_action_is_for_default_entry;
+	s->params.action_is_for_default_entry[s->params.n_actions] = action_is_for_default_entry;
+
 	s->params.n_actions++;
 
 	return 0;
