diff --git a/ansible/inventory/group_vars/all/bifrost b/ansible/inventory/group_vars/all/bifrost
index f99fcf486bda1d95ecf483365372959f23011339..4d2e41aec9572082d033de2ba2998ca4d74e4ac0 100644
--- a/ansible/inventory/group_vars/all/bifrost
+++ b/ansible/inventory/group_vars/all/bifrost
@@ -157,3 +157,7 @@ kolla_bifrost_ipa_ramdisk_checksum_algorithm: "{{ inspector_ipa_ramdisk_checksum
 
 # Server inventory for Bifrost.
 kolla_bifrost_servers: {}
+
+###############################################################################
+# Node provisioning configuration
+kolla_bifrost_use_introspection_mac: false
diff --git a/ansible/kolla-bifrost-hostvars.yml b/ansible/kolla-bifrost-hostvars.yml
index 9fbed026da50e4ccfcac6070086cc4675a904c52..120818131f6239d9516d0da1dadf5c0fe6e4616a 100644
--- a/ansible/kolla-bifrost-hostvars.yml
+++ b/ansible/kolla-bifrost-hostvars.yml
@@ -20,7 +20,7 @@
       addressing_mode: static
       deploy_image_filename: "{{ kolla_bifrost_deploy_image_filename }}"
       deploy_image_rootfs: "{{ kolla_bifrost_deploy_image_rootfs | default(omit, true) }}"
-      ipv4_interface_mac: "{% raw %}{{ extra.pxe_interface_mac | default }}{% endraw %}"
+      ipv4_interface_mac: "{% if kolla_bifrost_ipv4_interface_mac is defined %}{{ kolla_bifrost_ipv4_interface_mac }}{% else %}{% raw %}{{ extra.pxe_interface_mac | default }}{% endraw %}{% endif %}"
       ipv4_address: "{{ admin_oc_net_name | net_ip }}"
       ipv4_subnet_mask: "{{ admin_oc_net_name | net_mask }}"
       # If the admin network does not have a gateway defined and seed SNAT is
@@ -48,6 +48,36 @@
             force: True
           run_once: true
 
+        - block:
+            - name: Query overcloud nodes' hardware introspection data
+              command: >
+                docker exec bifrost_deploy
+                bash -c '
+                env BIFROST_INVENTORY_SOURCE=ironic BIFROST_NODE_NAMES="{{ inventory_hostname }}" OS_CLOUD=bifrost
+                ansible baremetal
+                --connection local
+                --inventory /etc/bifrost/inventory/
+                -e @/etc/bifrost/bifrost.yml
+                -e @/etc/bifrost/dib.yml
+                --limit {{ inventory_hostname }}
+                -m shell
+                -a "env OS_CLOUD=bifrost baremetal introspection data save {% raw %}{{ inventory_hostname }}{% endraw %}"'
+              register: save_result
+              changed_when: False
+              # Ignore errors, log a message later.
+              delegate_to: "{{ seed_host }}"
+              vars:
+                # NOTE: Without this, the seed's ansible_host variable will not be
+                # respected when using delegate_to.
+                ansible_host: "{{ hostvars[seed_host].ansible_host | default(seed_host) }}"
+
+            - name: Set interface MAC from Ironic introspection data
+              vars:
+                introspection_data: "{{ save_result.stdout_lines[1:] | join('\n') | from_json }}"
+              set_fact:
+                kolla_bifrost_ipv4_interface_mac: "{{ introspection_data.all_interfaces[admin_oc_net_name | net_physical_interface | first].mac }}"
+          when: kolla_bifrost_use_introspection_mac | bool
+
         - name: Ensure the Bifrost host variable files exist
           copy:
             content: |
diff --git a/doc/source/configuration/reference/bifrost.rst b/doc/source/configuration/reference/bifrost.rst
index 24f2aa3ed6073a1087693ce67fc14d1740b9bd77..6cdf6e0b8a81b452f7026983a1a47eda84a68967 100644
--- a/doc/source/configuration/reference/bifrost.rst
+++ b/doc/source/configuration/reference/bifrost.rst
@@ -34,6 +34,31 @@ For example, to install Bifrost from a custom git repository:
    kolla_bifrost_source_url: https://git.example.com/bifrost
    kolla_bifrost_source_version: downstream
 
+Bifrost interface configuration
+===============================
+
+Following option allows to configure ipv4 interface MAC for the provisioned
+server in cases where the default (PXE interface MAC) is not a suitable
+solution for admin network (e.g. separate interfaces for provisioning and
+admin):
+
+.. code-block:: yaml
+   :caption: ``bifrost.yml``
+
+   kolla_bifrost_use_introspection_mac: true
+
+It will cause the ``overloud provision`` command to query Bifrost's
+Introspection data for MAC address of the interface that is bound to admin
+network. Limitation of that option is that Kayobe will use the first
+physical NIC if the interface is bond or bridge.
+
+Alternatively you can set following in host_vars of a specific host:
+
+.. code-block:: yaml
+   :caption: ``host_vars``
+
+   kolla_bifrost_ipv4_interface_mac: "<mac_address_goes_here>"
+
 .. _configuration-bifrost-overcloud-root-image:
 
 Overcloud root disk image configuration
diff --git a/etc/kayobe/bifrost.yml b/etc/kayobe/bifrost.yml
index 123c53d231cd727c53a8372e0f0010840ec824f5..1f03b1a1a955baf809892bb360dda91d00251743 100644
--- a/etc/kayobe/bifrost.yml
+++ b/etc/kayobe/bifrost.yml
@@ -158,6 +158,12 @@
 # Server inventory for Bifrost.
 #kolla_bifrost_servers:
 
+###############################################################################
+# Node provisioning configuration
+# Whether to use Ironic introspection data for admin interface MAC address
+# Default is false.
+kolla_bifrost_use_introspection_mac:
+
 ###############################################################################
 # Dummy variable to allow Ansible to accept this file.
 workaround_ansible_issue_8743: yes
diff --git a/kayobe/plugins/filter/networks.py b/kayobe/plugins/filter/networks.py
index 97d4fd7e717827c39e062da9d03e62d4a859219a..bdf591c31d9581aba01d2a25652107f73861b70f 100644
--- a/kayobe/plugins/filter/networks.py
+++ b/kayobe/plugins/filter/networks.py
@@ -748,6 +748,19 @@ def net_ovs_veths(context, names, inventory_hostname=None):
         for veth in veths
     ]
 
+@jinja2.pass_context
+def net_physical_interface(context, name, inventory_hostname=None):
+    """Return a list of bridge ports, bond slaves or a direct interface name
+
+    Depending on the interface type - return a list of child interfaces or
+    (if it's not a bridge/bond) direct interface name.
+    """
+    if _net_interface_type(context, name, inventory_hostname) == 'bridge':
+        return net_bridge_ports(context, name, inventory_hostname)
+    elif  _net_interface_type(context, name, inventory_hostname) == 'bond':
+        return net_bond_slaves(context, name, inventory_hostname)
+    else:
+        return [net_attr(context, name, 'interface', inventory_hostname)]
 
 def get_filters():
     return {
@@ -799,4 +812,5 @@ def get_filters():
         'net_libvirt_network': net_libvirt_network,
         'net_libvirt_vm_network': net_libvirt_vm_network,
         'net_ovs_veths': net_ovs_veths,
+        'net_physical_interface': net_physical_interface,
     }
diff --git a/kayobe/tests/unit/plugins/filter/test_networks.py b/kayobe/tests/unit/plugins/filter/test_networks.py
index d8d786d5b9e660026a2de558d201ee36cfd222fd..c09d937a5c579f75ccde97dbf108355131da60a1 100644
--- a/kayobe/tests/unit/plugins/filter/test_networks.py
+++ b/kayobe/tests/unit/plugins/filter/test_networks.py
@@ -35,7 +35,7 @@ class BaseNetworksTest(unittest.TestCase):
         "net2_vlan": 2,
         # net3: bridge on br0 with ports eth0 and eth1.
         "net3_interface": "br0",
-        "net3_bridge_ports": [],
+        "net3_bridge_ports": ['eth0', 'eth1'],
         # net4: VLAN on br0.4 with VLAN 4 on bridge br0.
         "net4_interface": "br0.4",
         "net4_vlan": 4,
@@ -203,3 +203,20 @@ class TestNetworks(BaseNetworksTest):
         self._update_context({"net3_bridge_ports": "ens3"})
         self.assertRaises(errors.AnsibleFilterError, networks.net_bridge_ports,
                           self.context, "net3")
+
+    def test_physical_interface_bond(self):
+        self._update_context({"net6_interface": "bond0", "net6_bond_slaves": ["eth3", "eth4"]})
+        interface = networks.net_physical_interface(self.context, "net6")
+        expected = ['eth3', 'eth4']
+        self.assertEqual(expected, interface)
+
+    def test_physical_interface_bridge(self):
+        interface = networks.net_physical_interface(self.context, "net3")
+        expected = ['eth0', 'eth1']
+        self.assertEqual(expected, interface)
+
+    def test_physical_interface_direct(self):
+        interface = networks.net_physical_interface(self.context, "net1")
+        expected = ['eth0']
+        self.assertEqual(expected, interface)
+
diff --git a/releasenotes/notes/kolla-bifrost-use-introspection-mac-5765956eabc8366c.yaml b/releasenotes/notes/kolla-bifrost-use-introspection-mac-5765956eabc8366c.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9ef0cad68d1136b0fa9f30a48c3c6fa99fe5f5f5
--- /dev/null
+++ b/releasenotes/notes/kolla-bifrost-use-introspection-mac-5765956eabc8366c.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Adds support for using different interface than Bifrost PXE one for
+    admin interface during ``overcloud provision``.
+    This can be enabled by setting ``kolla_bifrost_use_introspection_mac``
+    to ``true`` or setting ``kolla_bifrost_ipv4_interface_mac`` in
+    respective host ``host_vars``.