diff --git a/app/api/inventory.py b/app/api/inventory.py
index 8827024e2d0320474b164b08e307a6449beb9fb1..abc2f0510710029bad28a0af232a64e027dae9af 100644
--- a/app/api/inventory.py
+++ b/app/api/inventory.py
@@ -72,6 +72,7 @@ def create_item():
     :jsonparam location: (optional) name of the location
     :jsonparam status: (optional) name of the status
     :jsonparam parent_id: (optional) parent id
+    :jsonparam host_id: (optional) host id
     """
     # People should assign an ICS id to a serial number when creating
     # an item so ics_id should also be a mandatory field.
diff --git a/app/api/network.py b/app/api/network.py
index d8e4239e72f0db5c8e0b5a181afd42595ec893ec..2079f585515052971c50ba08740b7e0531f1bd82 100644
--- a/app/api/network.py
+++ b/app/api/network.py
@@ -143,7 +143,7 @@ def create_host():
     :jsonparam name: hostname
     :jsonparam device_type: Physical|Virtual|...
     :jsonparam description: (optional) description
-    :jsonparam item_id: (optional) linked item primary key
+    :jsonparam items: (optional) list of items ICS id linked to the host
     """
     return create_generic_model(models.Host, mandatory_fields=('name', 'device_type'))
 
diff --git a/app/inventory/forms.py b/app/inventory/forms.py
index 1f40e0dc49828dfc8915c9cb06ed5dfcda67af79..a6fe0b57c3037dec521f8f4f3acef88fd457cc91 100644
--- a/app/inventory/forms.py
+++ b/app/inventory/forms.py
@@ -34,6 +34,7 @@ class ItemForm(CSEntryForm):
     location_id = SelectField('Location', coerce=utils.coerce_to_str_or_none)
     status_id = SelectField('Status', coerce=utils.coerce_to_str_or_none)
     parent_id = SelectField('Parent', coerce=utils.coerce_to_str_or_none)
+    host_id = SelectField('Host', coerce=utils.coerce_to_str_or_none)
     mac_addresses = StringField(
         'MAC addresses',
         description='space separated list of MAC addresses',
@@ -47,6 +48,7 @@ class ItemForm(CSEntryForm):
         self.location_id.choices = utils.get_model_choices(models.Location, allow_none=True)
         self.status_id.choices = utils.get_model_choices(models.Status, allow_none=True)
         self.parent_id.choices = utils.get_model_choices(models.Item, allow_none=True, attr='ics_id')
+        self.host_id.choices = utils.get_model_choices(models.Host, allow_none=True)
 
 
 class CommentForm(CSEntryForm):
diff --git a/app/inventory/views.py b/app/inventory/views.py
index 053577f2ec68742fe5599af43dbedce9a14496a4..9290fcc21674084c89e2b08af6e7fcc5721c9a88 100644
--- a/app/inventory/views.py
+++ b/app/inventory/views.py
@@ -130,7 +130,8 @@ def create_item():
                            model_id=form.model_id.data,
                            location_id=form.location_id.data,
                            status_id=form.status_id.data,
-                           parent_id=form.parent_id.data)
+                           parent_id=form.parent_id.data,
+                           host_id=form.host_id.data)
         item.macs = [models.Mac(address=address) for address in form.mac_addresses.data.split()]
         current_app.logger.debug(f'Trying to create: {item!r}')
         db.session.add(item)
@@ -179,7 +180,8 @@ def edit_item(ics_id):
             item.ics_id = form.ics_id.data
         item.serial_number = form.serial_number.data
         item.quantity = form.quantity.data
-        for key in ('manufacturer_id', 'model_id', 'location_id', 'status_id', 'parent_id'):
+        for key in ('manufacturer_id', 'model_id', 'location_id', 'status_id',
+                    'parent_id', 'host_id'):
             setattr(item, key, getattr(form, key).data)
         new_addresses = form.mac_addresses.data.split()
         # Delete the MAC addresses that have been removed
diff --git a/app/models.py b/app/models.py
index 9505953989f326e018711d47649daa977a31082c..b3b55e4493aa40d1e82978f57ee5a10038b57254 100644
--- a/app/models.py
+++ b/app/models.py
@@ -347,6 +347,7 @@ class Item(CreatedMixin, db.Model):
     location_id = db.Column(db.Integer, db.ForeignKey('location.id'))
     status_id = db.Column(db.Integer, db.ForeignKey('status.id'))
     parent_id = db.Column(db.Integer, db.ForeignKey('item.id'))
+    host_id = db.Column(db.Integer, db.ForeignKey('host.id'))
 
     manufacturer = db.relationship('Manufacturer', back_populates='items')
     model = db.relationship('Model', back_populates='items')
@@ -354,7 +355,6 @@ class Item(CreatedMixin, db.Model):
     status = db.relationship('Status', back_populates='items')
     children = db.relationship('Item', backref=db.backref('parent', remote_side=[id]))
     macs = db.relationship('Mac', backref='item')
-    host = db.relationship('Host', uselist=False, backref='item')
     comments = db.relationship('ItemComment', backref='item')
 
     def __init__(self, **kwargs):
@@ -392,6 +392,7 @@ class Item(CreatedMixin, db.Model):
             'parent': utils.format_field(self.parent),
             'children': [str(child) for child in self.children],
             'macs': [str(mac) for mac in self.macs],
+            'host': utils.format_field(self.host),
             'history': self.history(),
             'comments': [str(comment) for comment in self.comments],
         })
@@ -609,14 +610,18 @@ class Host(CreatedMixin, db.Model):
     name = db.Column(db.Text, nullable=False, unique=True)
     description = db.Column(db.Text)
     device_type_id = db.Column(db.Integer, db.ForeignKey('device_type.id'), nullable=False)
-    item_id = db.Column(db.Integer, db.ForeignKey('item.id'))
 
     interfaces = db.relationship('Interface', backref='host')
+    items = db.relationship('Item', backref='host')
 
     def __init__(self, **kwargs):
         # Automatically convert device_type as an instance of its class if passed as a string
         if 'device_type' in kwargs:
             kwargs['device_type'] = utils.convert_to_model(kwargs['device_type'], DeviceType)
+        # Automatically convert items to a list of instances if passed as a list of ics_id
+        if 'items' in kwargs:
+            kwargs['items'] = [utils.convert_to_model(item, Item, filter='ics_id')
+                               for item in kwargs['items']]
         super().__init__(**kwargs)
 
     def __str__(self):
@@ -639,7 +644,7 @@ class Host(CreatedMixin, db.Model):
             'name': self.name,
             'device_type': str(self.device_type),
             'description': self.description,
-            'item': utils.format_field(self.item),
+            'items': [str(item) for item in self.items],
             'interfaces': [str(interface) for interface in self.interfaces],
         })
         return d
diff --git a/app/network/forms.py b/app/network/forms.py
index ce2ab1b864eeb5d2822c8b0427c431c54bad448a..497174d0d3362c4a136f81908bbdebb18409d21d 100644
--- a/app/network/forms.py
+++ b/app/network/forms.py
@@ -126,12 +126,10 @@ class HostForm(CSEntryForm):
                        filters=[utils.lowercase_field])
     description = TextAreaField('Description')
     device_type_id = SelectField('Device Type')
-    item_id = SelectField('Item', coerce=utils.coerce_to_str_or_none)
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.device_type_id.choices = utils.get_model_choices(models.DeviceType)
-        self.item_id.choices = utils.get_model_choices(models.Item, allow_none=True, attr='ics_id')
 
 
 class InterfaceForm(CSEntryForm):
diff --git a/app/network/views.py b/app/network/views.py
index 8cc66ef860e5958d5800ccf3a9dfd1901be06ecc..be5780efaa2d86156f378055495ef866804da8e4 100644
--- a/app/network/views.py
+++ b/app/network/views.py
@@ -49,8 +49,7 @@ def create_host():
         network_id = form.network_id.data
         host = models.Host(name=form.name.data,
                            device_type_id=form.device_type_id.data,
-                           description=form.description.data or None,
-                           item_id=form.item_id.data)
+                           description=form.description.data or None)
         # The total number of tags will always be quite small
         # It's more efficient to retrieve all of them in one query
         # and do the filtering here
@@ -94,7 +93,6 @@ def edit_host(name):
     if form.validate_on_submit():
         host.name = form.name.data
         host.device_type_id = form.device_type_id.data
-        host.item_id = form.item_id.data
         host.description = form.description.data or None
         current_app.logger.debug(f'Trying to update: {host!r}')
         try:
diff --git a/app/static/js/hosts.js b/app/static/js/hosts.js
index 96df16c202fe237f4f406fc5280b6b620f12a435..9ec72da9f2548a1053c7fa598791014d37eec9c7 100644
--- a/app/static/js/hosts.js
+++ b/app/static/js/hosts.js
@@ -12,17 +12,12 @@ $(document).ready(function() {
     );
   }
 
-  // Enable / disable item_id field depending on device_type
-  // Item can only be assigned for physical hosts
   // And check / uncheck random_mac checkbox
   function update_device_type_attributes() {
     var device_type = $("#device_type_id option:selected").text();
     if( device_type.startsWith("Physical") ) {
-      $("#item_id").prop("disabled", false);
       $("#random_mac").prop("checked", false).change();
     } else {
-      $("#item_id").val("");
-      $("#item_id").prop("disabled", true);
       $("#random_mac").prop("checked", true).change();
     }
   }
diff --git a/app/templates/inventory/create_item.html b/app/templates/inventory/create_item.html
index 19e3f94b2a2e9bbb590a1d8a78b0ea418b0f2a4d..eac63e1b9f55129fecf50e8ee0dd6cc261dca0d5 100644
--- a/app/templates/inventory/create_item.html
+++ b/app/templates/inventory/create_item.html
@@ -16,6 +16,7 @@
         {{ render_field(form.location_id) }}
         {{ render_field(form.status_id) }}
         {{ render_field(form.parent_id) }}
+        {{ render_field(form.host_id) }}
         {{ render_field(form.mac_addresses) }}
         <div class="form-group row">
           <div class="col-sm-10">
diff --git a/app/templates/inventory/edit_item.html b/app/templates/inventory/edit_item.html
index 9a2b187c87a155b0ee317564396b383b3d47e66c..3797048b9f8b098082976311c32500bd13dba784 100644
--- a/app/templates/inventory/edit_item.html
+++ b/app/templates/inventory/edit_item.html
@@ -28,6 +28,7 @@
     {{ render_field(form.location_id) }}
     {{ render_field(form.status_id) }}
     {{ render_field(form.parent_id) }}
+    {{ render_field(form.host_id) }}
     {{ render_field(form.mac_addresses) }}
     <div class="form-group row">
       <div class="col-sm-10">
diff --git a/app/templates/network/create_host.html b/app/templates/network/create_host.html
index f228a9d305d7ad40ce9bb217b57991ef4a8f895c..7b13bdbf02ee58db0a4829228115320e3ac44860 100644
--- a/app/templates/network/create_host.html
+++ b/app/templates/network/create_host.html
@@ -10,7 +10,6 @@
     {{ render_field(form.name, class_="text-lowercase") }}
     {{ render_field(form.device_type_id) }}
     {{ render_field(form.description) }}
-    {{ render_field(form.item_id, disabled=True) }}
     {{ render_field(form.network_id) }}
     {{ render_field(form.ip) }}
     {{ render_field(form.random_mac) }}
diff --git a/app/templates/network/edit_host.html b/app/templates/network/edit_host.html
index fb4c2cd72d10c71536de67b7a38db128a55213b3..866f12a606991e7514c9e38850b19a0323528a22 100644
--- a/app/templates/network/edit_host.html
+++ b/app/templates/network/edit_host.html
@@ -21,7 +21,6 @@
     {{ render_field(form.name, class_="text-lowercase") }}
     {{ render_field(form.device_type_id) }}
     {{ render_field(form.description) }}
-    {{ render_field(form.item_id) }}
     <div class="form-group row">
       <div class="col-sm-10">
         <button type="submit" class="btn btn-primary">Submit</button>
diff --git a/app/templates/network/view_host.html b/app/templates/network/view_host.html
index 6da69299d49bd8eb491dbeb9de1803ac8e6b81aa..6d60c7475ebab76caf9ef2be5e203875a7de3259 100644
--- a/app/templates/network/view_host.html
+++ b/app/templates/network/view_host.html
@@ -1,5 +1,5 @@
 {% extends "network/hosts.html" %}
-{% from "_helpers.html" import link_to_item, delete_button_with_confirmation %}
+{% from "_helpers.html" import link_to_items, delete_button_with_confirmation %}
 
 {% block title %}View Host - CSEntry{% endblock %}
 
@@ -21,9 +21,9 @@
     <dd class="col-sm-9">{{ host.name }}</dd>
     <dt class="col-sm-3">Device Type</dt>
     <dd class="col-sm-9">{{ host.device_type }}</dd>
-    {% if host.device_type.name == 'Physical' %}
-    <dt class="col-sm-3">Item</dt>
-    <dd class="col-sm-9">{{ link_to_item(host.item) }}</dd>
+    {% if host.items %}
+    <dt class="col-sm-3">Items</dt>
+    <dd class="col-sm-9">{{ link_to_items(host.items) }}</dd>
     {% endif %}
     <dt class="col-sm-3">Description</dt>
     <dd class="col-sm-9">{{ host.description }}</dd>
diff --git a/migrations/versions/7ffb5fbbd0f0_allow_to_associate_several_items_to_one_.py b/migrations/versions/7ffb5fbbd0f0_allow_to_associate_several_items_to_one_.py
new file mode 100644
index 0000000000000000000000000000000000000000..a19dea20c42ce872a1634b2e027ee395776e8284
--- /dev/null
+++ b/migrations/versions/7ffb5fbbd0f0_allow_to_associate_several_items_to_one_.py
@@ -0,0 +1,48 @@
+"""Allow to associate several items to one host
+
+Revision ID: 7ffb5fbbd0f0
+Revises: e07c7bc870be
+Create Date: 2018-04-20 12:01:25.242815
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = '7ffb5fbbd0f0'
+down_revision = 'e07c7bc870be'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.add_column('item', sa.Column('host_id', sa.Integer(), nullable=True))
+    op.create_foreign_key(op.f('fk_item_host_id_host'), 'item', 'host', ['host_id'], ['id'])
+    op.add_column('item_version', sa.Column('host_id', sa.Integer(), autoincrement=False, nullable=True))
+    # Fill the item host_id based on the old host item_id value
+    conn = op.get_bind()
+    res = conn.execute('SELECT id, item_id FROM host WHERE item_id IS NOT NULL')
+    results = res.fetchall()
+    item = sa.sql.table('item', sa.sql.column('id'), sa.sql.column('host_id'))
+    for result in results:
+        op.execute(item.update().where(item.c.id == result[1]).values(host_id=result[0]))
+    # We can drop the item_id column now
+    op.drop_constraint('fk_host_item_id_item', 'host', type_='foreignkey')
+    op.drop_column('host', 'item_id')
+
+
+def downgrade():
+    op.add_column('host', sa.Column('item_id', sa.INTEGER(), autoincrement=False, nullable=True))
+    op.create_foreign_key('fk_host_item_id_item', 'host', 'item', ['item_id'], ['id'])
+    # Fill the host item_id based on the item host_id value
+    conn = op.get_bind()
+    res = conn.execute('SELECT id, host_id FROM item WHERE host_id IS NOT NULL')
+    results = res.fetchall()
+    host = sa.sql.table('host', sa.sql.column('id'), sa.sql.column('item_id'))
+    for result in results:
+        op.execute(host.update().where(host.c.id == result[1]).values(item_id=result[0]))
+    # Drop the unused columns
+    op.drop_column('item_version', 'host_id')
+    op.drop_constraint(op.f('fk_item_host_id_host'), 'item', type_='foreignkey')
+    op.drop_column('item', 'host_id')
diff --git a/migrations/versions/ac6b3c416b07_add_machine_type_table.py b/migrations/versions/ac6b3c416b07_add_machine_type_table.py
index a2ff1cab60b3f02455104043ccad687e05f2cd25..6adb797c8aa7e17e84e4f844050b46d18f550f9b 100644
--- a/migrations/versions/ac6b3c416b07_add_machine_type_table.py
+++ b/migrations/versions/ac6b3c416b07_add_machine_type_table.py
@@ -25,7 +25,7 @@ def upgrade():
         sa.PrimaryKeyConstraint('id', name=op.f('pk_machine_type')),
         sa.UniqueConstraint('name', name=op.f('uq_machine_type_name'))
     )
-    # WARNING! If the database is not emppty, we can't set the machine_type_id to nullable=False before adding a value!
+    # WARNING! If the database is not empty, we can't set the machine_type_id to nullable=False before adding a value!
     op.add_column('host', sa.Column('machine_type_id', sa.Integer(), nullable=True))
     op.create_foreign_key(op.f('fk_host_machine_type_id_machine_type'), 'host', 'machine_type', ['machine_type_id'], ['id'])
     # Create the Physical and Virtual machine types
diff --git a/tests/functional/test_api.py b/tests/functional/test_api.py
index 1393553cbc44c4a7eb1c74daedd002a2c03c959e..33835cef9db8fd5c9270d215f6e1020a78c27741 100644
--- a/tests/functional/test_api.py
+++ b/tests/functional/test_api.py
@@ -216,7 +216,7 @@ def test_create_item(client, user_token):
     response = post(client, f'{API_URL}/inventory/items', data=data, token=user_token)
     assert response.status_code == 201
     assert {'id', 'ics_id', 'serial_number', 'manufacturer', 'model', 'quantity',
-            'location', 'status', 'parent', 'children', 'macs', 'history',
+            'location', 'status', 'parent', 'children', 'macs', 'history', 'host',
             'updated_at', 'created_at', 'user', 'comments'} == set(response.json.keys())
     assert response.json['serial_number'] == '123456'
 
@@ -237,6 +237,17 @@ def test_create_item(client, user_token):
     check_input_is_subset_of_response(response, (data, data, data2))
 
 
+def test_create_item_with_host_id(client, host_factory, user_token):
+    host = host_factory()
+    # Check that we can pass an host_id
+    data = {'serial_number': '123456',
+            'host_id': host.id}
+    response = post(client, f'{API_URL}/inventory/items', data=data, token=user_token)
+    assert response.status_code == 201
+    item = models.Item.query.filter_by(serial_number=data['serial_number']).first()
+    assert item.host_id == host.id
+
+
 def test_create_item_invalid_ics_id(client, user_token):
     for ics_id in ('foo', 'AAB1234', 'AZ02', 'WS007', 'AAA01'):
         data = {'serial_number': '123456', 'ics_id': ics_id}
@@ -758,8 +769,7 @@ def test_get_hosts(client, host_factory, readonly_token):
     check_input_is_subset_of_response(response, (host1.to_dict(), host2.to_dict()))
 
 
-def test_create_host(client, item_factory, device_type_factory, user_token):
-    item = item_factory()
+def test_create_host(client, device_type_factory, user_token):
     device_type = device_type_factory(name='Virtual')
     # check that name and device_type are  mandatory
     response = post(client, f'{API_URL}/network/hosts', data={}, token=user_token)
@@ -774,7 +784,7 @@ def test_create_host(client, item_factory, device_type_factory, user_token):
     response = post(client, f'{API_URL}/network/hosts', data=data, token=user_token)
     assert response.status_code == 201
     assert {'id', 'name', 'device_type', 'description',
-            'item', 'interfaces', 'created_at',
+            'items', 'interfaces', 'created_at',
             'updated_at', 'user'} == set(response.json.keys())
     assert response.json['name'] == data['name']
 
@@ -782,15 +792,23 @@ def test_create_host(client, item_factory, device_type_factory, user_token):
     response = post(client, f'{API_URL}/network/hosts', data=data, token=user_token)
     check_response_message(response, '(psycopg2.IntegrityError) duplicate key value violates unique constraint', 422)
 
-    # Check that we can pass an item_id
-    data2 = {'name': 'another-hostname',
-             'device_type': device_type.name,
-             'item_id': item.id}
-    response = post(client, f'{API_URL}/network/hosts', data=data2, token=user_token)
-    assert response.status_code == 201
+    # check that the number of items created
+    assert models.Host.query.count() == 1
 
-    # check that all items were created
-    assert models.Host.query.count() == 2
+
+def test_create_host_with_items(client, item_factory, device_type_factory, user_token):
+    device_type = device_type_factory(name='Switch')
+    item1 = item_factory(ics_id='AAA001')
+    item2 = item_factory(ics_id='AAA002')
+    # Check that we can pass a list of items ics_id
+    data = {'name': 'my-switch',
+            'device_type': device_type.name,
+            'items': [item1.ics_id, item2.ics_id]}
+    response = post(client, f'{API_URL}/network/hosts', data=data, token=user_token)
+    assert response.status_code == 201
+    host = models.Host.query.filter_by(name='my-switch').first()
+    assert models.Item.query.get(item1.id).host_id == host.id
+    assert models.Item.query.get(item2.id).host_id == host.id
 
 
 def test_create_host_as_consultant(client, item_factory, device_type_factory, consultant_token):