diff --git a/northd/northd.c b/northd/northd.c
index 2efc4bb1f..1831e6e79 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -592,6 +592,7 @@ struct ovn_datapath {
     uint32_t port_key_hint;
 
     bool has_stateful_acl;
+    bool has_stateless_acl;
     bool has_lb_vip;
     bool has_unknown;
     bool has_acls;
@@ -5416,15 +5417,26 @@ ls_get_acl_flags(struct ovn_datapath *od)
 {
     od->has_acls = false;
     od->has_stateful_acl = false;
+    od->has_stateless_acl = false;
 
     if (od->nbs->n_acls) {
         od->has_acls = true;
 
         for (size_t i = 0; i < od->nbs->n_acls; i++) {
             struct nbrec_acl *acl = od->nbs->acls[i];
-            if (!strcmp(acl->action, "allow-related")) {
+            if (!od->has_stateful_acl &&
+                !strcmp(acl->action, "allow-related")) {
                 od->has_stateful_acl = true;
-                return;
+                if (od->has_stateless_acl) {
+                    return;
+                }
+            }
+            if (!od->has_stateless_acl &&
+                !strcmp(acl->action, "allow-stateless")) {
+                od->has_stateless_acl = true;
+                if (od->has_stateful_acl) {
+                    return;
+                }
             }
         }
     }
@@ -5436,9 +5448,19 @@ ls_get_acl_flags(struct ovn_datapath *od)
 
             for (size_t i = 0; i < ls_pg->nb_pg->n_acls; i++) {
                 struct nbrec_acl *acl = ls_pg->nb_pg->acls[i];
-                if (!strcmp(acl->action, "allow-related")) {
+                if (!od->has_stateful_acl &&
+                    !strcmp(acl->action, "allow-related")) {
                     od->has_stateful_acl = true;
-                    return;
+                    if (od->has_stateless_acl) {
+                        return;
+                    }
+                }
+                if (!od->has_stateless_acl &&
+                    !strcmp(acl->action, "allow-stateless")) {
+                    od->has_stateless_acl = true;
+                    if (od->has_stateful_acl) {
+                        return;
+                    }
                 }
             }
         }
@@ -5647,45 +5669,42 @@ skip_port_from_conntrack(struct ovn_datapath *od, struct ovn_port *op,
 }
 
 static void
-build_stateless_filter(struct ovn_datapath *od,
-                       const struct nbrec_acl *acl,
-                       struct hmap *lflows)
+build_acl_filter(struct ovn_datapath *od, const struct nbrec_acl *acl,
+                 struct hmap *lflows)
 {
+    int direction;
+    char *actions;
+
     if (!strcmp(acl->direction, "from-lport")) {
-        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_IN_PRE_ACL,
-                                acl->priority + OVN_ACL_PRI_OFFSET,
-                                acl->match,
-                                "next;",
-                                &acl->header_);
+        direction = S_SWITCH_IN_PRE_ACL;
     } else {
-        ovn_lflow_add_with_hint(lflows, od, S_SWITCH_OUT_PRE_ACL,
-                                acl->priority + OVN_ACL_PRI_OFFSET,
-                                acl->match,
-                                "next;",
-                                &acl->header_);
+        direction = S_SWITCH_OUT_PRE_ACL;
+    }
+
+    if (!strcmp(acl->action, "allow-stateless")) {
+        actions = "next;";
+    } else {
+        actions = REGBIT_CONNTRACK_DEFRAG" = 1; next;";
     }
+
+    ovn_lflow_add_with_hint(lflows, od, direction,
+                            acl->priority + OVN_ACL_PRI_OFFSET, acl->match,
+                            actions, &acl->header_);
 }
 
 static void
-build_stateless_filters(struct ovn_datapath *od,
-                        const struct hmap *port_groups,
-                        struct hmap *lflows)
+build_acl_filters(struct ovn_datapath *od, const struct hmap *port_groups,
+                  struct hmap *lflows)
 {
     for (size_t i = 0; i < od->nbs->n_acls; i++) {
-        const struct nbrec_acl *acl = od->nbs->acls[i];
-        if (!strcmp(acl->action, "allow-stateless")) {
-            build_stateless_filter(od, acl, lflows);
-        }
+        build_acl_filter(od, od->nbs->acls[i], lflows);
     }
 
     struct ovn_port_group *pg;
     HMAP_FOR_EACH (pg, key_node, port_groups) {
         if (ovn_port_group_ls_find(pg, &od->nbs->header_.uuid)) {
             for (size_t i = 0; i < pg->nb_pg->n_acls; i++) {
-                const struct nbrec_acl *acl = pg->nb_pg->acls[i];
-                if (!strcmp(acl->action, "allow-stateless")) {
-                    build_stateless_filter(od, acl, lflows);
-                }
+                build_acl_filter(od, pg->nb_pg->acls[i], lflows);
             }
         }
     }
@@ -5700,10 +5719,10 @@ build_pre_acls(struct ovn_datapath *od, const struct hmap *port_groups,
     ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
     ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;");
 
-    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
+    ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 65535,
                   "eth.dst == $svc_monitor_mac", "next;");
 
-    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
+    ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 65535,
                   "eth.src == $svc_monitor_mac", "next;");
 
     /* If there are any stateful ACL rules in this datapath, we may
@@ -5713,25 +5732,26 @@ build_pre_acls(struct ovn_datapath *od, const struct hmap *port_groups,
         for (size_t i = 0; i < od->n_router_ports; i++) {
             skip_port_from_conntrack(od, od->router_ports[i],
                                      S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
-                                     110, lflows);
+                                     65535, lflows);
         }
         for (size_t i = 0; i < od->n_localnet_ports; i++) {
             skip_port_from_conntrack(od, od->localnet_ports[i],
                                      S_SWITCH_IN_PRE_ACL, S_SWITCH_OUT_PRE_ACL,
-                                     110, lflows);
+                                     65535, lflows);
         }
 
-        /* stateless filters always take precedence over stateful ACLs. */
-        build_stateless_filters(od, port_groups, lflows);
+        if (od->has_stateless_acl) {
+            build_acl_filters(od, port_groups, lflows);
+        }
 
         /* Ingress and Egress Pre-ACL Table (Priority 110).
          *
          * Not to do conntrack on ND and ICMP destination
          * unreachable packets. */
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
+        ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 65535,
                       "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
-        ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
+        ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 65535,
                       "nd || nd_rs || nd_ra || mldv1 || mldv2 || "
                       "(udp && udp.src == 546 && udp.dst == 547)", "next;");
 
diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
index bd3c3aa26..f92906e5b 100644
--- a/northd/ovn-northd.8.xml
+++ b/northd/ovn-northd.8.xml
@@ -459,7 +459,9 @@
       priority-110 flow is added to skip over stateful ACLs. IPv6 Neighbor
       Discovery and MLD traffic also skips stateful ACLs. For "allow-stateless"
       ACLs, a flow is added to bypass setting the hint for connection tracker
-      processing.
+      processing.  If datapath has "allow-stateless" and "allow-related" ACLs,
+      a flow for each ACL would be added with priority value calculated as 1000
+      plus ACL's priority and action <code>reg0[0] = 1; next;</code>.
     </p>
 
     <p>
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index c4424ab14..b168b79c9 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -3100,7 +3100,7 @@ AT_CLEANUP
 ])
 
 OVN_FOR_EACH_NORTHD([
-AT_SETUP([ACL allow-stateless overrides stateful rules with higher priority - Logical_Switch])
+AT_SETUP([ACL allow-stateless doesn't override stateful rules with higher priority - Logical_Switch])
 ovn_start
 
 ovn-nbctl ls-add ls
@@ -3110,22 +3110,29 @@ ovn-nbctl lsp-add ls lsp2
 ovn-nbctl lsp-set-addresses lsp2 00:00:00:00:00:02
 
 for direction in from to; do
-    ovn-nbctl acl-add ls ${direction}-lport 3 "tcp" allow-related
-    ovn-nbctl acl-add ls ${direction}-lport 3 "udp" allow
+    ovn-nbctl acl-add ls ${direction}-lport 3 "ip4.src == 10.0.0.0/24 && tcp" allow-related
+    ovn-nbctl acl-add ls ${direction}-lport 3 "ip4.src == 10.0.0.0/24 && udp" allow
+done
+
+# Allow stateless with *lower* priority. It should not override stateful rules.
+for direction in from to; do
+    ovn-nbctl acl-add ls ${direction}-lport 1 tcp allow-stateless
+    ovn-nbctl acl-add ls ${direction}-lport 1 udp allow-stateless
 done
 ovn-nbctl --wait=sb sync
 
 flow_eth='eth.src == 00:00:00:00:00:01 && eth.dst == 00:00:00:00:00:02'
-flow_ip='ip.ttl==64 && ip4.src == 42.42.42.1 && ip4.dst == 66.66.66.66'
+flow_ip_10='ip.ttl==64 && ip4.src == 10.0.0.1 && ip4.dst == 66.66.66.66'
+flow_ip_20='ip.ttl==64 && ip4.src == 20.0.0.1 && ip4.dst == 66.66.66.66'
 flow_tcp='tcp && tcp.dst == 80'
 flow_udp='udp && udp.dst == 80'
 
 lsp1_inport=$(fetch_column Port_Binding tunnel_key logical_port=lsp1)
 
-# TCP packets should go to conntrack.
-flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
+# TCP and UDP packets should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_10} && ${flow_tcp}"
 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
-# tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
+# tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=10.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
 ct_next(ct_state=new|trk) {
     ct_next(ct_state=new|trk) {
         output("lsp2");
@@ -3133,24 +3140,25 @@ ct_next(ct_state=new|trk) {
 };
 ])
 
-# Allow stateless with *lower* priority. It always beats stateful rules.
-for direction in from to; do
-    ovn-nbctl acl-add ls ${direction}-lport 1 tcp allow-stateless
-    ovn-nbctl acl-add ls ${direction}-lport 1 udp allow-stateless
-done
-ovn-nbctl --wait=sb sync
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_10} && ${flow_udp}"
+AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
+# udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=10.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
+ct_next(ct_state=new|trk) {
+    ct_next(ct_state=new|trk) {
+        output("lsp2");
+    };
+};
+])
 
-# TCP packets should not go to conntrack anymore.
-flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_tcp}"
+# TCP and UDP packets from 20.0.0.1 should go to conntrack.
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_20} && ${flow_tcp}"
 AT_CHECK_UNQUOTED([ovn-trace --minimal ls "${flow}"], [0], [dnl
-# tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
+# tcp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=20.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
 output("lsp2");
 ])
-
-# UDP packets should not go to conntrack anymore.
-flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip} && ${flow_udp}"
+flow="inport == \"lsp1\" && ${flow_eth} && ${flow_ip_20} && ${flow_udp}"
 AT_CHECK_UNQUOTED([ovn-trace --ct new --ct new --minimal ls "${flow}"], [0], [dnl
-# udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=42.42.42.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
+# udp,reg14=0x${lsp1_inport},vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=20.0.0.1,nw_dst=66.66.66.66,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80
 output("lsp2");
 ])
 
