}
 
        ste->ste_chain_location = orig_ste->ste_chain_location;
+       ste->htbl->pointing_ste = orig_ste->htbl->pointing_ste;
 
        /* In collision entry, all members share the same miss_list_head */
        ste->htbl->miss_list = mlx5dr_ste_get_miss_list(orig_ste);
        if (!new_ste)
                return NULL;
 
+       /* Update collision pointing STE */
+       new_ste->htbl->pointing_ste = col_ste->htbl->pointing_ste;
+
        /* In collision entry, all members share the same miss_list_head */
        new_ste->htbl->miss_list = mlx5dr_ste_get_miss_list(col_ste);
 
        new_ste->next_htbl = cur_ste->next_htbl;
        new_ste->ste_chain_location = cur_ste->ste_chain_location;
 
-       if (!mlx5dr_ste_is_last_in_rule(nic_matcher, new_ste->ste_chain_location))
+       if (new_ste->next_htbl)
                new_ste->next_htbl->pointing_ste = new_ste;
 
        /* We need to copy the refcount since this ste
         */
        new_ste->refcount = cur_ste->refcount;
 
-       /* Link old STEs rule_mem list to the new ste */
-       mlx5dr_rule_update_rule_member(cur_ste, new_ste);
-       INIT_LIST_HEAD(&new_ste->rule_list);
-       list_splice_tail_init(&cur_ste->rule_list, &new_ste->rule_list);
+       /* Link old STEs rule to the new ste */
+       mlx5dr_rule_set_last_member(cur_ste->rule_rx_tx, new_ste, false);
 }
 
 static struct mlx5dr_ste *
        return -ENOMEM;
 }
 
-/* While the pointer of ste is no longer valid, like while moving ste to be
- * the first in the miss_list, and to be in the origin table,
- * all rule-members that are attached to this ste should update their ste member
- * to the new pointer
- */
-void mlx5dr_rule_update_rule_member(struct mlx5dr_ste *ste,
-                                   struct mlx5dr_ste *new_ste)
+void mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx *nic_rule,
+                                struct mlx5dr_ste *ste,
+                                bool force)
+{
+       /* Update rule member is usually done for the last STE or during rule
+        * creation to recover from mid-creation failure (for this peruse the
+        * force flag is used)
+        */
+       if (ste->next_htbl && !force)
+               return;
+
+       /* Update is required since each rule keeps track of its last STE */
+       ste->rule_rx_tx = nic_rule;
+       nic_rule->last_rule_ste = ste;
+}
+
+static struct mlx5dr_ste *dr_rule_get_pointed_ste(struct mlx5dr_ste *curr_ste)
+{
+       struct mlx5dr_ste *first_ste;
+
+       first_ste = list_first_entry(mlx5dr_ste_get_miss_list(curr_ste),
+                                    struct mlx5dr_ste, miss_list_node);
+
+       return first_ste->htbl->pointing_ste;
+}
+
+int mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste **ste_arr,
+                                        struct mlx5dr_ste *curr_ste,
+                                        int *num_of_stes)
 {
-       struct mlx5dr_rule_member *rule_mem;
+       bool first = false;
+
+       *num_of_stes = 0;
+
+       if (!curr_ste)
+               return -ENOENT;
+
+       /* Iterate from last to first */
+       while (!first) {
+               first = curr_ste->ste_chain_location == 1;
+               ste_arr[*num_of_stes] = curr_ste;
+               *num_of_stes += 1;
+               curr_ste = dr_rule_get_pointed_ste(curr_ste);
+       }
 
-       list_for_each_entry(rule_mem, &ste->rule_list, use_ste_list)
-               rule_mem->ste = new_ste;
+       return 0;
 }
 
 static void dr_rule_clean_rule_members(struct mlx5dr_rule *rule,
                                       struct mlx5dr_rule_rx_tx *nic_rule)
 {
-       struct mlx5dr_rule_member *rule_mem;
-       struct mlx5dr_rule_member *tmp_mem;
+       struct mlx5dr_ste *ste_arr[DR_RULE_MAX_STES + DR_ACTION_MAX_STES];
+       struct mlx5dr_ste *curr_ste = nic_rule->last_rule_ste;
+       int i;
 
-       if (list_empty(&nic_rule->rule_members_list))
+       if (mlx5dr_rule_get_reverse_rule_members(ste_arr, curr_ste, &i))
                return;
-       list_for_each_entry_safe(rule_mem, tmp_mem, &nic_rule->rule_members_list, list) {
-               list_del(&rule_mem->list);
-               list_del(&rule_mem->use_ste_list);
-               mlx5dr_ste_put(rule_mem->ste, rule->matcher, nic_rule->nic_matcher);
-               kvfree(rule_mem);
-       }
+
+       while (i--)
+               mlx5dr_ste_put(ste_arr[i], rule->matcher, nic_rule->nic_matcher);
 }
 
 static u16 dr_get_bits_per_mask(u16 byte_mask)
        return false;
 }
 
-static int dr_rule_add_member(struct mlx5dr_rule_rx_tx *nic_rule,
-                             struct mlx5dr_ste *ste)
-{
-       struct mlx5dr_rule_member *rule_mem;
-
-       rule_mem = kvzalloc(sizeof(*rule_mem), GFP_KERNEL);
-       if (!rule_mem)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&rule_mem->list);
-       INIT_LIST_HEAD(&rule_mem->use_ste_list);
-
-       rule_mem->ste = ste;
-       list_add_tail(&rule_mem->list, &nic_rule->rule_members_list);
-
-       list_add_tail(&rule_mem->use_ste_list, &ste->rule_list);
-
-       return 0;
-}
-
 static int dr_rule_handle_action_stes(struct mlx5dr_rule *rule,
                                      struct mlx5dr_rule_rx_tx *nic_rule,
                                      struct list_head *send_ste_list,
        struct mlx5dr_domain *dmn = matcher->tbl->dmn;
        u8 *curr_hw_ste, *prev_hw_ste;
        struct mlx5dr_ste *action_ste;
-       int i, k, ret;
+       int i, k;
 
        /* Two cases:
         * 1. num_of_builders is equal to new_hw_ste_arr_sz, the action in the ste
         * 2. num_of_builders is less then new_hw_ste_arr_sz, new ste was added
         *    to support the action.
         */
-       if (num_of_builders == new_hw_ste_arr_sz)
-               return 0;
 
        for (i = num_of_builders, k = 0; i < new_hw_ste_arr_sz; i++, k++) {
                curr_hw_ste = hw_ste_arr + i * DR_STE_SIZE;
 
                mlx5dr_ste_get(action_ste);
 
+               action_ste->htbl->pointing_ste = last_ste;
+               last_ste->next_htbl = action_ste->htbl;
+               last_ste = action_ste;
+
                /* While free ste we go over the miss list, so add this ste to the list */
                list_add_tail(&action_ste->miss_list_node,
                              mlx5dr_ste_get_miss_list(action_ste));
                mlx5dr_ste_set_hit_addr_by_next_htbl(dmn->ste_ctx,
                                                     prev_hw_ste,
                                                     action_ste->htbl);
-               ret = dr_rule_add_member(nic_rule, action_ste);
-               if (ret) {
-                       mlx5dr_dbg(dmn, "Failed adding rule member\n");
-                       goto free_ste_info;
-               }
+
+               mlx5dr_rule_set_last_member(nic_rule, action_ste, true);
+
                mlx5dr_send_fill_and_append_ste_send_info(action_ste, DR_STE_SIZE, 0,
                                                          curr_hw_ste,
                                                          ste_info_arr[k],
                                                          send_ste_list, false);
        }
 
+       last_ste->next_htbl = NULL;
+
        return 0;
 
-free_ste_info:
-       kfree(ste_info_arr[k]);
 err_exit:
        mlx5dr_ste_put(action_ste, matcher, nic_matcher);
        return -ENOMEM;
        nic_matcher = nic_rule->nic_matcher;
        nic_dmn = nic_matcher->nic_tbl->nic_dmn;
 
-       INIT_LIST_HEAD(&nic_rule->rule_members_list);
-
        if (dr_rule_skip(dmn->type, nic_dmn->type, &matcher->mask, param,
                         rule->flow_source))
                return 0;
 
                cur_htbl = ste->next_htbl;
 
-               /* Keep all STEs in the rule struct */
-               ret = dr_rule_add_member(nic_rule, ste);
-               if (ret) {
-                       mlx5dr_dbg(dmn, "Failed adding rule member index %d\n", i);
-                       goto free_ste;
-               }
-
                mlx5dr_ste_get(ste);
+               mlx5dr_rule_set_last_member(nic_rule, ste, true);
        }
 
        /* Connect actions */
 
        return 0;
 
-free_ste:
-       mlx5dr_ste_put(ste, matcher, nic_matcher);
 free_rule:
        dr_rule_clean_rule_members(rule, nic_rule);
        /* Clean all ste_info's */
 
 struct mlx5dr_ste_htbl;
 struct mlx5dr_match_param;
 struct mlx5dr_cmd_caps;
+struct mlx5dr_rule_rx_tx;
 struct mlx5dr_matcher_rx_tx;
 struct mlx5dr_ste_ctx;
 
        /* attached to the miss_list head at each htbl entry */
        struct list_head miss_list_node;
 
-       /* each rule member that uses this ste attached here */
-       struct list_head rule_list;
-
        /* this ste is member of htbl */
        struct mlx5dr_ste_htbl *htbl;
 
        struct mlx5dr_ste_htbl *next_htbl;
 
+       /* The rule this STE belongs to */
+       struct mlx5dr_rule_rx_tx *rule_rx_tx;
+
        /* this ste is part of a rule, located in ste's chain */
        u8 ste_chain_location;
 };
        struct mlx5dv_flow_matcher *dv_matcher;
 };
 
-struct mlx5dr_rule_member {
-       struct mlx5dr_ste *ste;
-       /* attached to mlx5dr_rule via this */
-       struct list_head list;
-       /* attached to mlx5dr_ste via this */
-       struct list_head use_ste_list;
-};
-
 struct mlx5dr_ste_action_modify_field {
        u16 hw_field;
        u8 start;
 };
 
 struct mlx5dr_rule_rx_tx {
-       struct list_head rule_members_list;
        struct mlx5dr_matcher_rx_tx *nic_matcher;
+       struct mlx5dr_ste *last_rule_ste;
 };
 
 struct mlx5dr_rule {
        u32 flow_source;
 };
 
-void mlx5dr_rule_update_rule_member(struct mlx5dr_ste *new_ste,
-                                   struct mlx5dr_ste *ste);
+void mlx5dr_rule_set_last_member(struct mlx5dr_rule_rx_tx *nic_rule,
+                                struct mlx5dr_ste *ste,
+                                bool force);
+int mlx5dr_rule_get_reverse_rule_members(struct mlx5dr_ste **ste_arr,
+                                        struct mlx5dr_ste *curr_ste,
+                                        int *num_of_stes);
 
 struct mlx5dr_icm_chunk {
        struct mlx5dr_icm_buddy_mem *buddy_mem;