diff --git a/lib/walberla/experimental/lbm/GenericHbbBoundary.hpp b/lib/walberla/experimental/lbm/GenericHbbBoundary.hpp
index aad3c4bcb383d7cf2aeb5341f5ec3cb57a82c83e..54a536fa5a6dd9f7f9d1c6f9f7fb153625d80157 100644
--- a/lib/walberla/experimental/lbm/GenericHbbBoundary.hpp
+++ b/lib/walberla/experimental/lbm/GenericHbbBoundary.hpp
@@ -16,93 +16,92 @@
 
 #include "walberla/experimental/sweep/SparseIndexList.hpp"
 
-namespace walberla::experimental
-{
-namespace lbm
+namespace walberla::experimental::lbm
 {
 
 struct HbbLink
 {
-  int32_t x;
-  int32_t y;
-  int32_t z;
-  int32_t dir;
-
-  /**
-   * Create a halfway bounce-back boundary link from a fluid cell `c` to a boundary cell in direction `d`.
-   */
-  HbbLink(const Cell& c, const stencil::Direction d)
-    : x{ int32_c(c.x()) }, y{ int32_c(c.y()) }, z{ int32_c(c.z()) }, dir{ int32_t(d) }
-  {}
-
-  bool operator==(const HbbLink& other) const
-  {
-    return std::tie(x, y, z, dir) == std::tie(other.x, other.y, other.z, other.dir);
-  }
+   int32_t x;
+   int32_t y;
+   int32_t z;
+   int32_t dir;
+
+   /**
+    * Create a halfway bounce-back boundary link from a fluid cell `c` to a boundary cell in direction `d`.
+    */
+   HbbLink(const Cell& c, const stencil::Direction d)
+      : x{ int32_c(c.x()) }, y{ int32_c(c.y()) }, z{ int32_c(c.z()) }, dir{ int32_t(d) }
+   {}
+
+   bool operator==(const HbbLink& other) const
+   {
+      return std::tie(x, y, z, dir) == std::tie(other.x, other.y, other.z, other.dir);
+   }
 };
 
-/**
- * @brief Boundary index list for half-way bounce-back boundary conditions
- */
-template< typename Stencil_T >
-class GenericHbbBoundary
+template< typename Impl >
+struct GenericHbbFactoryImplTraits
 {
-public:
-  using Stencil      = Stencil_T;
-  using IndexVectors = sweep::internal::IndexListBuffer< HbbLink >;
-
-  GenericHbbBoundary(StructuredBlockForest& blocks)
-  {
-    auto createIdxVector = [](IBlock* const, StructuredBlockStorage* const) { return new IndexVectors(); };
-    indexVectorsId_      = blocks.addStructuredBlockData< IndexVectors >(createIdxVector);
-  }
-
-  template< typename FlagField_T >
-  void fillFromFlagField(StructuredBlockForest& blocks, ConstBlockDataID flagFieldID,
-                         FlagUID boundaryFlagUID, FlagUID domainFlagUID)
-  {
-    for (auto & block: blocks)
-      fillFromFlagField< FlagField_T >(block, flagFieldID, boundaryFlagUID, domainFlagUID);
-  }
-
-  template< typename FlagField_T >
-  void fillFromFlagField(IBlock& block, ConstBlockDataID flagFieldID, FlagUID boundaryFlagUID, FlagUID domainFlagUID);
-
-protected:
-  BlockDataID indexVectorsId_;
+   using Stencil_T         = typename Impl::Stencil;
+   using IdxStruct_T       = HbbLink;
+   using IndexListMemTag_T = typename Impl::memtag_t;
+   using IndexList_T       = sweep::SparseIndexList< IdxStruct_T, IndexListMemTag_T >;
 };
 
-template< typename Stencil_T >
-template< typename FlagField_T >
-void GenericHbbBoundary< Stencil_T >::fillFromFlagField(IBlock& block, ConstBlockDataID flagFieldID,
-                                                                FlagUID boundaryFlagUID, FlagUID domainFlagUID)
+template< typename Impl >
+class GenericHbbFactory
 {
-  auto* indexVectors   = block.getData< IndexVectors >(indexVectorsId_);
-  auto& indexVectorAll = indexVectors->vector();
-  auto* flagField      = block.getData< FlagField_T >(flagFieldID);
+   using ImplTraits = GenericHbbFactoryImplTraits< Impl >;
+
+ public:
+   GenericHbbFactory(const shared_ptr< StructuredBlockForest > blocks, BlockDataID pdfFieldID)
+      : blocks_{ blocks }, pdfFieldID_{ pdfFieldID }
+   {}
+
+   template< typename FlagField_T >
+   auto fromFlagField(BlockDataID flagFieldID, field::FlagUID boundaryFlagUID, field::FlagUID fluidFlagUID)
+   {
+      using flag_t = typename FlagField_T::flag_t;
+      using IndexList_T = typename ImplTraits::IndexList_T;
+      using Stencil = typename ImplTraits::Stencil_T;
+
+      IndexList_T indexList{ *blocks_ };
 
-  if (!(flagField->flagExists(boundaryFlagUID) && flagField->flagExists(domainFlagUID))) return;
+      for (auto& block : *blocks_)
+      {
+         FlagField_T* flagField = block.getData< FlagField_T >(flagFieldID);
+         flag_t boundaryFlag{ flagField->getFlag(boundaryFlagUID) };
+         flag_t fluidFlag{ flagField->getFlag(fluidFlagUID) };
 
-  auto boundaryFlag = flagField->getFlag(boundaryFlagUID);
-  auto domainFlag   = flagField->getFlag(domainFlagUID);
+         if (!(flagField->flagExists(boundaryFlagUID) && flagField->flagExists(fluidFlagUID))) continue;
 
-  indexVectorAll.clear();
+         auto& idxVector = indexList.getVector(block);
 
-  const cell_idx_t numGhostLayers = cell_idx_c(flagField->nrOfGhostLayers() - 1);
-  for (auto it = flagField->beginWithGhostLayerXYZ(numGhostLayers); it != flagField->end(); ++it)
-  {
-    const Cell fluidCell{ it.cell() };
+         for (auto it = flagField->beginXYZ(); it != flagField->end(); ++it)
+         {
+            Cell fluidCell{ it.cell() };
+            if (!isFlagSet(it, fluidFlag)) { continue; }
 
-    if (!isFlagSet(it, domainFlag)) continue;
+            for (auto dIt = Stencil::beginNoCenter(); dIt != Stencil::end(); ++dIt)
+            {
+               stencil::Direction dir{ *dIt };
+               Cell neighbor{ fluidCell + dir };
+               if (flagField->isFlagSet(neighbor, boundaryFlag)) { idxVector.emplace_back(fluidCell, dir); }
+            }
+         }
+      }
 
-    for (auto dIt = Stencil::beginNoCenter(); dIt != Stencil::end(); ++dIt)
-    {
-      const stencil::Direction dir{ *dIt };
+      return impl().irregularFromIndexVector(indexList);
+   }
 
-      if (isFlagSet(it.neighbor(dir), boundaryFlag)) { indexVectorAll.emplace_back(fluidCell, dir); }
-    }
-  }
-}
+ protected:
+   shared_ptr< StructuredBlockForest > blocks_;
+   BlockDataID pdfFieldID_;
+
+ private:
+   Impl& impl() { return *static_cast< Impl* >(this); }
+
+   const Impl& impl() const { return *static_cast< const Impl* >(this); }
+};
 
-} // namespace sfg
-} // namespace walberla
+} // namespace walberla::experimental::lbm
diff --git a/src/walberla/codegen/boundaries/__init__.py b/src/walberla/codegen/boundaries/__init__.py
index b505fbeaf0ac2e2353f5f7aec9ed71e3334c25bd..4364cb21aab5d7e712f8773c5f3f8363e2fe8b1c 100644
--- a/src/walberla/codegen/boundaries/__init__.py
+++ b/src/walberla/codegen/boundaries/__init__.py
@@ -1,4 +1,3 @@
-from .hbb import SimpleHbbBoundary
-from .linkwise import NoSlip, FreeSlip
+from .linkwise import NoSlip, FreeSlip, GenericHBB
 
-__all__ = ["SimpleHbbBoundary", "NoSlip", "FreeSlip"]
+__all__ = ["NoSlip", "FreeSlip", "GenericHBB"]
diff --git a/src/walberla/codegen/boundaries/boundary_utils.py b/src/walberla/codegen/boundaries/boundary_utils.py
index 453d611cba1fa1c4bb7891f921befe6fd68867a2..e3ce6b0b29550b7c1221cb0533b4f63345e4c2d1 100644
--- a/src/walberla/codegen/boundaries/boundary_utils.py
+++ b/src/walberla/codegen/boundaries/boundary_utils.py
@@ -1,4 +1,6 @@
 from functools import cache
+from typing import Any
+from abc import abstractmethod
 
 from pystencils import Field, FieldType, TypedSymbol, Assignment
 from pystencils.types import PsStructType, create_type
@@ -35,6 +37,9 @@ class WalberlaLbmBoundary:
             (TypedSymbol("indexVectorLength", BoundaryIndexType), 1),
             (1, 1),
         )
+    
+    @abstractmethod
+    def boundary_obj(self) -> LbBoundary: ...
 
     def get_assignments(
         self,
@@ -43,8 +48,6 @@ class WalberlaLbmBoundary:
         prev_timestep: Timestep = Timestep.BOTH,
         streaming_pattern="pull",
     ) -> list[Assignment]:
-        assert isinstance(self, LbBoundary)
-
         index_field = self.get_index_field()
 
         from lbmpy.advanced_streaming.indexing import BetweenTimestepsIndexing
@@ -62,7 +65,7 @@ class WalberlaLbmBoundary:
         dir_symbol = indexing.dir_symbol
         inv_dir = indexing.inverse_dir_symbol
 
-        boundary_assignments = self(
+        boundary_assignments = self.boundary_obj()(
             f_out,
             f_in,
             dir_symbol,
@@ -78,10 +81,20 @@ class WalberlaLbmBoundary:
         index_arrs_node = indexing.create_code_node()
         elements += index_arrs_node.get_array_declarations()
 
-        for node in self.get_additional_code_nodes(lb_method)[::-1]:
+        for node in self.boundary_obj().get_additional_code_nodes(lb_method)[::-1]:
             elements += node.get_array_declarations()
 
         elements += [Assignment(dir_symbol, index_field[0]("dir"))]
         elements += boundary_assignments.all_assignments
 
         return elements
+
+
+class GenericHbbWrapper(WalberlaLbmBoundary):
+    idx_struct_type = HbbLinkType
+
+    def __init__(self, hbb: LbBoundary):
+        self._hbb = hbb
+
+    def boundary_obj(self) -> LbBoundary:
+        return self._hbb
diff --git a/src/walberla/codegen/boundaries/hbb.py b/src/walberla/codegen/boundaries/hbb.py
deleted file mode 100644
index c249667fc374021a0d9ab8d4ab9c8d60c12d299e..0000000000000000000000000000000000000000
--- a/src/walberla/codegen/boundaries/hbb.py
+++ /dev/null
@@ -1,202 +0,0 @@
-"""Code generation for half-way bounce-back LBM boundary conditions in waLBerla"""
-
-from pystencils import Field, FieldType, TypedSymbol, Target, AssignmentCollection
-
-from pystencilssfg import SfgComposer
-from pystencilssfg.composer.class_composer import SfgClassComposer
-from pystencilssfg.composer.custom import CustomGenerator
-from pystencilssfg.lang import AugExpr
-
-from lbmpy.methods import AbstractLbMethod
-from lbmpy.boundaries.boundaryconditions import LbBoundary
-from lbmpy.advanced_streaming.indexing import Timestep
-
-from ..sweep import (
-    GlFieldInfo,
-    SweepClassProperties,
-    BlockforestParameters,
-    combine_vectors,
-)
-from ..api import GhostLayerFieldPtr, BlockDataID, IBlockPtr, StructuredBlockForest, IndexListBufferPtr
-from .boundary_utils import HbbLinkType, BoundaryIndexType
-
-
-class HbbBoundaryProperties(SweepClassProperties):
-    def _constructor(self, sfg: SfgComposer) -> SfgClassComposer.ConstructorBuilder:
-        blocks = StructuredBlockForest.shared_ptr_ref()
-        return sfg.constructor(blocks).init("GenericHbbBoundary")(
-            AugExpr.format("*{}", blocks)
-        )
-
-
-class SimpleHbbBoundary(CustomGenerator):
-    def __init__(self, bc: LbBoundary, lb_method: AbstractLbMethod, pdf_field: Field):
-        if bc.additional_data:
-            raise ValueError(
-                "The SimpleHbbBoundary generator only supports boundary conditions without "
-                "additional per-link data."
-            )
-
-        self._bc = bc
-        self._name = bc.name
-        self._lb_method = lb_method
-        self._pdf_field = pdf_field
-        self._index_field = self._get_index_field()
-        self._stencil = lb_method.stencil
-
-    def generate(self, sfg: SfgComposer) -> None:
-        sfg.include("walberla/experimental/lbm/GenericHbbBoundary.hpp")
-        sfg.include(f"stencil/{self._stencil.name}.h")
-
-        knamespace = sfg.kernel_namespace(f"{self._name}_kernels")
-        bc_kernel = _create_lb_boundary_kernel(
-            self._pdf_field, self._get_index_field(), self._lb_method, self._bc
-        )
-
-        khandle = knamespace.add(bc_kernel, self._name)
-
-        domain_fields: list[GlFieldInfo] = sorted(
-            (
-                GlFieldInfo(
-                    f, GhostLayerFieldPtr.create(f), BlockDataID().var(f"{f.name}Id")
-                )
-                for f in khandle.fields
-                if f.field_type == FieldType.GENERIC
-            ),
-            key=lambda f: f.field.name,
-        )
-
-        props = HbbBoundaryProperties()
-        block = IBlockPtr().var("block")
-
-        parameters = khandle.scalar_parameters
-
-        blockforest_params = BlockforestParameters(props, block, None)
-        parameters = blockforest_params.filter_params(parameters)
-
-        vector_groups = combine_vectors(parameters)
-
-        for fi in domain_fields:
-            props.add_property(fi.data_id, setter=False, getter=True)
-
-        for s in sorted(parameters, key=lambda p: p.name):
-            props.add_property(s, setter=True, getter=True)
-
-        idx_vector = IndexListBufferPtr(HbbLinkType).var("indexVector")
-        idx_vector_id = BlockDataID().bind("this->indexVectorsId_")
-
-        base_class = f"walberla::experimental::lbm::GenericHbbBoundary< walberla::stencil::{self._stencil.name} >"
-
-        sfg.klass(self._name, bases=[f"public {base_class}"])(
-            *props.render(sfg),
-            sfg.public(
-                sfg.method("operator()")(
-                    #   Get block data IDs for fields
-                    *(
-                        sfg.init(fi.data_id)(props.get(fi.data_id))
-                        for fi in domain_fields
-                    ),
-                    #   Get fields from block
-                    *(
-                        sfg.init(fi.wlb_field)(
-                            block.getData(fi.wlb_field.field_type, fi.data_id)
-                        )
-                        for fi in domain_fields
-                    ),
-                    #   Map GhostLayerFields to pystencils fields
-                    *(sfg.map_field(fi.field, fi.wlb_field) for fi in domain_fields),
-                    #   Get index vector
-                    sfg.init(idx_vector)(
-                        block.getData(idx_vector.field_type, idx_vector_id)
-                    ),
-                    #   Map index vector to pystencils field
-                    sfg.map_field(self._index_field, idx_vector),
-                    #   Extract parameters
-                    *(sfg.init(param)(props.get(param)) for param in parameters),
-                    #   Extract vector components
-                    *(
-                        sfg.map_vector(comps, vec)
-                        for vec, comps in vector_groups.items()
-                    ),
-                    #   Extract geometry information
-                    *(blockforest_params.render_extractions(sfg)),
-                    #   Call kernel
-                    sfg.call(khandle),
-                )
-            ),
-        )
-
-    def _get_index_field(self) -> Field:
-        return Field(
-            "indexField",
-            FieldType.INDEXED,
-            HbbLinkType,
-            (0,),
-            (TypedSymbol("index_vector_length", BoundaryIndexType), 1),
-            (1, 1),
-        )
-
-
-def _create_lb_boundary_kernel(
-    pdf_field: Field,
-    index_field,
-    lb_method,
-    boundary_functor,
-    prev_timestep=Timestep.BOTH,
-    streaming_pattern="pull",
-    target=Target.CPU,
-    **kernel_creation_args,
-):
-    """Almost-copy of `lbmpy.boundaryhandling.create_lattice_boltzmann_boundary_kernel`,
-    extended with waLBerla-specific function expansion."""
-
-    from lbmpy.advanced_streaming.indexing import BetweenTimestepsIndexing
-
-    indexing = BetweenTimestepsIndexing(
-        pdf_field, lb_method.stencil, prev_timestep, streaming_pattern, "int32", "int32"
-    )
-
-    f_out, f_in = indexing.proxy_fields
-    dir_symbol = indexing.dir_symbol
-    inv_dir = indexing.inverse_dir_symbol
-
-    boundary_assignments = boundary_functor(
-        f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, None  # TODO: Fix force vector
-    )
-    boundary_assignments = indexing.substitute_proxies(boundary_assignments)
-
-    from pystencils.types.quick import SInt
-    from pystencils import CreateKernelConfig, Assignment, create_kernel
-    from pystencils.simp import add_subexpressions_for_field_reads
-
-    config = CreateKernelConfig(
-        index_field=index_field,
-        target=target,
-        index_dtype=SInt(32),
-        default_dtype=pdf_field.dtype,  # type: ignore
-        skip_independence_check=True,
-        **kernel_creation_args,
-    )
-
-    default_data_type = config.default_dtype
-    if pdf_field.dtype != default_data_type:
-        boundary_assignments = add_subexpressions_for_field_reads(
-            boundary_assignments, data_type=default_data_type
-        )
-
-    elements: list[Assignment] = []
-
-    index_arrs_node = indexing.create_code_node()
-    elements += index_arrs_node.get_array_declarations()
-
-    for node in boundary_functor.get_additional_code_nodes(lb_method)[::-1]:
-        elements += node.get_array_declarations()
-
-    elements += [Assignment(dir_symbol, index_field[0]("dir"))]
-    elements += boundary_assignments.all_assignments
-
-    asms = AssignmentCollection(elements)
-    asms = BlockforestParameters.process(asms)
-
-    kernel = create_kernel(asms, config=config)
-    return kernel
diff --git a/src/walberla/codegen/boundaries/linkwise.py b/src/walberla/codegen/boundaries/linkwise.py
index a82e9b444e45d0832039acfd4726cc7f92bfa9b8..04a6491ba0712f4f17b55d386757f89cf83e4070 100644
--- a/src/walberla/codegen/boundaries/linkwise.py
+++ b/src/walberla/codegen/boundaries/linkwise.py
@@ -4,6 +4,7 @@ from pystencils import (
     CreateKernelConfig,
     Target,
     AssignmentCollection,
+    FieldType,
 )
 from pystencils.types import PsStructType
 
@@ -13,7 +14,7 @@ from lbmpy.boundaries.boundaryconditions import LbBoundary
 from pystencilssfg import SfgComposer
 from pystencilssfg.composer.custom import CustomGenerator
 
-from .hbb import BoundaryIndexType
+from .boundary_utils import BoundaryIndexType, GenericHbbWrapper
 from .boundary_utils import WalberlaLbmBoundary
 from ..sweep import Sweep
 from ..api import SparseIndexList, MemTags
@@ -107,6 +108,97 @@ class NoSlip(GenericLinkwiseBoundary):
         return AssignmentCollection(asms)
 
 
+class GenericHBB(GenericLinkwiseBoundary):
+    def __init__(
+        self,
+        bc: LbBoundary,
+        lb_method: AbstractLbMethod,
+        pdf_field: Field,
+        target: Target | None = None,
+    ):
+        if bc.additional_data:
+            raise ValueError(
+                "The SimpleHbbBoundary generator only supports boundary conditions without "
+                "additional per-link data."
+            )
+
+        self._bc = GenericHbbWrapper(bc)
+        self._name = bc.name
+        self._lb_method = lb_method
+        self._pdf_field = pdf_field
+        self._stencil = lb_method.stencil
+        self._target = target
+
+    @property
+    def target(self) -> Target | None:
+        return self._target
+
+    @target.setter
+    def target(self, t: Target | None):
+        self._target = t
+
+    def generate(self, sfg: SfgComposer) -> None:
+        return self._generate_irregular(sfg)
+
+    def _generate_irregular(self, sfg: SfgComposer):
+        sfg.include("walberla/experimental/lbm/GenericHbbBoundary.hpp")
+
+        #   Get assignments for bc
+        bc_obj = self._bc
+        bc_asm = bc_obj.get_assignments(self._lb_method, self._pdf_field)
+
+        #   Build generator config
+        bc_cfg = CreateKernelConfig(target=self._target)
+        bc_cfg.index_dtype = BoundaryIndexType
+        index_field = bc_obj.get_index_field()
+        bc_cfg.index_field = index_field
+
+        #   Prepare sweep
+        bc_sweep = Sweep(self._name, bc_asm, bc_cfg)
+
+        #   Emit code
+        sfg.generate(bc_sweep)
+
+        #   Build factory
+        factory_name = f"{self._name}Factory"
+        factory_crtp_base = (
+            f"walberla::experimental::lbm::GenericHbbFactory< {factory_name} >"
+        )
+        memtag_t = MemTags.unified if bc_cfg.get_target().is_gpu() else MemTags.host
+        index_vector = SparseIndexList(
+            GenericHbbWrapper.idx_struct_type, memtag_t=memtag_t, ref=True
+        ).var("indexVector")
+
+        sweep_type = bc_sweep.generated_class()
+        sweep_ctor_args = {
+            f"{self._pdf_field.name}Id": "this->pdfFieldID_",
+            f"{index_field.name}": index_vector,
+        }
+
+        stencil_name = self._lb_method.stencil.name
+        sfg.include(f"stencil/{stencil_name}.h")
+
+        sfg.klass(factory_name, bases=[f"public {factory_crtp_base}"])(
+            sfg.public(
+                f"using Base = {factory_crtp_base};",
+                f"friend class {factory_crtp_base};",
+                f"using Stencil = walberla::stencil::{stencil_name};",
+                f"using Sweep = {sweep_type.get_dtype().c_string()};",
+                f"using memtag_t = {memtag_t.c_string()};" "using Base::Base;",
+            ),
+            sfg.private(
+                sfg.method(
+                    "irregularFromIndexVector",
+                )
+                .returns(sweep_type.get_dtype())
+                .inline()(sfg.expr("return {};", sweep_type.ctor(**sweep_ctor_args))),
+            ),
+        )
+
+    def _generate_regular(self, sfg: SfgComposer):
+        assert False
+
+
 class FreeSlip(GenericLinkwiseBoundary):
     """Specular-reflection half-way bounce back boundary condition.
 
@@ -195,8 +287,7 @@ class FreeSlip(GenericLinkwiseBoundary):
                 f"friend class {factory_crtp_base};",
                 f"using Stencil = walberla::stencil::{stencil_name};",
                 f"using Sweep = {sweep_type.get_dtype().c_string()};",
-                f"using memtag_t = {memtag_t.c_string()};"
-                "using Base::Base;",
+                f"using memtag_t = {memtag_t.c_string()};" "using Base::Base;",
             ),
             sfg.private(
                 sfg.method(
@@ -262,6 +353,9 @@ class WalberlaIrregularFreeSlip(LbBoundary, WalberlaLbmBoundary):
         "walberla::experimental::lbm::IrregularFreeSlipLinkInfo",
     )
 
+    def boundary_obj(self) -> LbBoundary:
+        return self
+
     def __call__(
         self, f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector
     ):
diff --git a/user_manual/examples/ForceDrivenChannel/ForceDrivenChannel.cpp b/user_manual/examples/ForceDrivenChannel/ForceDrivenChannel.cpp
index 2871b8d363703cba9fb93bddb69469b3e5ae103a..f87b21e243f489a63df9f5d2b20c25e472dcd14f 100644
--- a/user_manual/examples/ForceDrivenChannel/ForceDrivenChannel.cpp
+++ b/user_manual/examples/ForceDrivenChannel/ForceDrivenChannel.cpp
@@ -86,12 +86,13 @@ namespace Ex_ForceDrivenChannel
         auto flagFieldOutput = field::createVTKOutput<FlagField_T>(flagFieldId, *blocks, "flagField", 1, 0);
         flagFieldOutput();
 
-        auto noSlip = make_unique<gen::NoSlip>(blocks, pdfsId);
-        noSlip->fillFromFlagField<FlagField_T>(*blocks, flagFieldId, noSlipFlagUid, fluidFlagUid);
+        gen::NoSlip noSlip {
+            gen::NoSlipFactory(blocks, pdfsId).fromFlagField< FlagField_T >(flagFieldId, noSlipFlagUid, fluidFlagUid)
+        };
 
         auto boundarySweep = [&](IBlock *block)
         {
-            (*noSlip)(block);
+            noSlip(block);
         };
 
         //  Timeloop
diff --git a/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py b/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py
index af4285acf81e2a7104d50813908c2f611223cdf0..6289568aa40c49b1f56560db34676c12eb9abe5b 100644
--- a/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py
+++ b/user_manual/examples/ForceDrivenChannel/LbmAlgorithms.py
@@ -3,7 +3,7 @@ import pystencils as ps
 
 from pystencilssfg import SourceFileGenerator
 from walberla.codegen import Sweep
-from walberla.codegen.boundaries import SimpleHbbBoundary
+from walberla.codegen.boundaries import GenericHBB
 
 from lbmpy import (
     LBStencil,
@@ -21,7 +21,8 @@ from lbmpy.macroscopic_value_kernels import macroscopic_values_setter
 stencil = LBStencil(Stencil.D3Q19)
 dim = stencil.D
 f, f_tmp, rho, u = ps.fields(
-    f"f({stencil.Q}), f_tmp({stencil.Q}), rho(1), u({dim}): double[{dim}D]", layout="fzyx"
+    f"f({stencil.Q}), f_tmp({stencil.Q}), rho(1), u({dim}): double[{dim}D]",
+    layout="fzyx",
 )
 omega = sp.Symbol("omega")
 force = sp.symbols(f"F_:{dim}")
@@ -46,8 +47,9 @@ with SourceFileGenerator() as sfg:
 
     lbm_opt = LBMOptimisation(symbolic_field=f, symbolic_temporary_field=f_tmp)
 
-    gen_config = ps.CreateKernelConfig()
-    gen_config.target = ps.Target.CPU
+    target = ps.Target.GenericCPU
+
+    gen_config = ps.CreateKernelConfig(target=target)
     gen_config.cpu.openmp.enable = True
 
     lb_update = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt)
@@ -62,4 +64,4 @@ with SourceFileGenerator() as sfg:
     sfg.generate(lb_init_sweep)
 
     #   No-Slip Wall
-    sfg.generate(SimpleHbbBoundary(NoSlip(), lb_method, f))
+    sfg.generate(GenericHBB(NoSlip(), lb_method, f, target=target))
diff --git a/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py b/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
index dddace06a9f0e447924b00da023f52958a7a2bfc..a7f5521a54facc081498c55e4ca72aeb433bbe0f 100644
--- a/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
+++ b/user_manual/examples/FreeSlipBubble/LbmAlgorithms.py
@@ -1,7 +1,7 @@
 import sympy as sp
 from pystencilssfg import SourceFileGenerator
 
-from pystencils import fields, Field
+from pystencils import fields, Field, Target, CreateKernelConfig
 from lbmpy import LBStencil, Stencil, LBMConfig, LBMOptimisation, create_lb_update_rule
 from lbmpy.macroscopic_value_kernels import macroscopic_values_setter
 
@@ -28,11 +28,14 @@ with SourceFileGenerator() as sfg:
         symbolic_temporary_field=pdfs_tmp,
     )
 
+    target = Target.GenericCPU
+    cfg = CreateKernelConfig(target=target)
+
     lb_update = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt)
     lb_method = lb_update.method
     assert lb_update is not None
 
-    lb_update_sweep = Sweep("LbStreamCollide", lb_update)
+    lb_update_sweep = Sweep("LbStreamCollide", lb_update, cfg)
     lb_update_sweep.swap_fields(pdfs, pdfs_tmp)
     sfg.generate(lb_update_sweep)
 
@@ -42,7 +45,7 @@ with SourceFileGenerator() as sfg:
         velocity=sp.symbols(f"velocity_:{d}"),
         pdfs=pdfs,
     )
-    lb_init_sweep = Sweep("LbInit", lb_init)
+    lb_init_sweep = Sweep("LbInit", lb_init, cfg)
     sfg.generate(lb_init_sweep)
 
     #   begin irregular-freeslip
@@ -53,6 +56,7 @@ with SourceFileGenerator() as sfg:
         lb_method,
         pdfs,
         wall_normal=FreeSlip.IRREGULAR,
+        target=target
     )
 
     sfg.generate(freeslip)