Non-overlapping rectangles constrained to a boundary
Basic answer

I suggest to use the geometric type box and combine that with an exclusion constraint (Postgres 9.2+). Should be the perfect solution to your problem. The GiST index this is implemented with (automatically) also supports certain queries.

Combine it with with equality on board_id to hold multiple boards in a single table. You'll need the additional module btree_gist. Once per database:

CREATE EXTENSION btree_gist;


To confine parts to a board add a CHECK constraint. You need the confining box of the board in the board_part table (redundantly). Could look like this:

CREATE TABLE board_part (
   board_id bigint NOT NULL references board
  ,board_box box NOT NULL
  ,part_id bigint NOT NULL references part
  ,part_box box NOT NULL
  ,EXCLUDE USING gist (board_id WITH =, part_box WITH &amp;&amp;)
  ,CHECK (part_box &lt;@ board_box)
);


&amp;&amp; .. "overlaps" operator; &lt;@ .. "contained" operator

The drawback: you need the dimensions of each part and box in table board_part redundantly. 

Advanced answer

To avoid redundant storage, I like this new idea better: Fake IMMUTABLE functions returning the box for an id and build constraints upon these functions. Your tables can make do with just the columns of your original design.

I ran a complete test to verify it works. 

Complete schema

Base tables:

CREATE TABLE part (
   part_id serial PRIMARY KEY
  ,part text NOT NULL
  ,wide int NOT NULL
  ,high int NOT NULL
);

CREATE TABLE board (
  board_id serial PRIMARY KEY
 ,board text NOT NULL
 ,wide int NOT NULL
 ,high int NOT NULL
);


IMMUTABLE Functions:

CREATE OR REPLACE FUNCTION f_boardbox(_board_id int)
  RETURNS box AS
'SELECT box(point(0,0), point (b.wide, b.high))
 FROM public.board b WHERE board_id = $1'
LANGUAGE sql IMMUTABLE; 

CREATE OR REPLACE FUNCTION f_partbox(_part_id int, _wide int, _high int)
  RETURNS box AS
'SELECT box(point($2,$3), point($2 + p.wide, $3 + p.high))
 FROM public.part p WHERE part_id = $1'
LANGUAGE sql IMMUTABLE;


Replace public with the actual schema of your tables.

Main table:

CREATE TABLE board_part (
  board_id int NOT NULL REFERENCES board
 ,part_id int NOT NULL REFERENCES part
 ,wide int NOT NULL
 ,high int NOT NULL
 ,EXCLUDE USING gist (board_id WITH =, f_partbox(part_id, wide, high) WITH &amp;&amp;)
 ,CHECK (f_partbox(part_id, wide, high) &lt;@ f_boardbox(board_id))
);


Of course, if you update dimensions for a board_id or part_id in use, you partly void the index and / or constraint. You would need to recreate any index or constraint building on the promise that the return value of IMMUTABLE function never change. More explanation for the technique in this related answer on SO:
Does PostgreSQL support “accent insensitive” collations?

However, you can avoid this expensive operation with triggers to update only affected rows:

Triggers

CREATE OR REPLACE FUNCTION f_board_upaft()
  RETURNS trigger AS
$func$
BEGIN
   UPDATE  board_part
   SET     board_id = board_id       -- enough to trigger CHECK constraint
   WHERE   board_id = NEW.board_id;  -- limit to relevant rows

   RETURN NULL;
END
$func$ LANGUAGE plpgsql;

CREATE TRIGGER board_upaft
AFTER UPDATE OF wide, high ON board  -- limit to relevant columns
FOR EACH ROW EXECUTE PROCEDURE f_board_upaft();


CREATE OR REPLACE FUNCTION f_part_upaft()
  RETURNS trigger AS
$func$
BEGIN
   UPDATE  board_part
   SET     part_id = 0
   WHERE   part_id = NEW.part_id;

   UPDATE  board_part
   SET     part_id = NEW.part_id
   WHERE   part_id = 0;              -- enough to update EXCL. constraint

   RETURN NULL;
END
$func$
  LANGUAGE plpgsql;

CREATE TRIGGER part_upaft
AFTER UPDATE OF wide, high ON part
FOR EACH ROW EXECUTE PROCEDURE f_part_upaft();


part_id = 0 is a special row in table part with size 0. Needed for the trigger.

Test data:

INSERT INTO board (board, wide, high)
VALUES ('b1010',10,10), ('b2030',20, 30);

INSERT INTO part (part_id, part, wide, high)
VALUES (0,'p0',0,0);          -- special row needed for trigger!

INSERT INTO part (part, wide, high)
VALUES ('p11',1,1), ('p33',3,3);

INSERT INTO board_part (board_id, part_id, wide, high)
VALUES (1,1,3,3), (1,1,5,5)   -- no overlap, inside board
      ,(2,1,3,3);             -- different board, no overlap


Test

These must raise exceptions if the triggers &amp; constraints do their job:

UPDATE part SET wide = 6 , high = 6
WHERE  part_id = 1;            -- violates EXCL. &amp; CHECK constraint

UPDATE part SET wide = 3 , high = 3
WHERE  part_id = 1;            -- violates EXCL. constraint

UPDATE board SET wide = 2 , high = 2
WHERE  board_id = 1;            -- violates CHECK constraint


Its not possible to install extensions on SQLfiddle, so simplified exclusion constraint without btree_gist: SQLfiddle to play with.