Constraint spanning several tables Imagine the following tables:

Products (Id, Name, ...)

Used for storing products

ProductVersions (Id, Version, ReleasedOn)

Used for storing a version history of a single product (v1.0, v2.0, v3.0, ...)

Customers (Id, ForeName, ...)

Well, yeah. Used for storing customers.

Now a single customer can have multiple products. That requires another table:

CustomerProducts (Id, CustomerId, ???)

What is the best approach here? Should I reference  to the Products table (ProductId) or the ProductVersions table (ProductVersionId)?

In terms of joining I'd have access to the Product entity when querying over the ProductVersion of a customer (Customer -> ProductVersion -> Product)

I know it is dependant on my very own design (so if a user owns a product or a version of a product), but what's the best way in general? What if a user can own an entire Product (Product1), but only owns Version 3.0 of Product2?
On product what you have is a Type 2, Slowly Changing Dimension. 

A More in-depth discussion on Slowly Changing Dimensions here

A model for this would look something like the following:


Customer stays as is.

Product has a hierarchy (self referencing to the parent [previous version]
Product has a different ProductId for each version. 

You did not mention whether multiple versions are valid at the same time. 
Let us assume not.

Valid_From:Valid_To are one way to identify when a product is valid. The 'current' product version has the valid_from set, but valid_to NULL. 

When it is time to move to the next 'Version':


Update the current records Valid_To date timestamp to now()
Get the next ProductId (nextval on a sequence ususally)
Get the next Version number (derived from the current version
number)
Insert new record into Product, valid_From to now(), use new version
number, reference the old parentId in the Parent_prodid
Commit


You will get new ProductIds for each version, but you will be able to give details of the product/customer relationship over time.

'ownership' of a product may be assigned at any version number. You can cascade the ownership from by maintaining the appropriate CUST_PRODUCT entries, they can be singular (for a specific version) or multiple for all or a subset of the versions.

You can find all versions by cascading thru the self referencing structure until you get the first (oldest, smallest version number, ...)